From c2eb5171f2f00fb51071ee2971ae4543d6a78e3b Mon Sep 17 00:00:00 2001 From: mattebit Date: Wed, 19 Jul 2023 14:43:05 +0200 Subject: [PATCH] Removed Utils class, moved all the enums to proper class --- doc/language.md | 5 +- tool/.idea/compiler.xml | 2 +- tool/src/main/java/migt/BurpExtender.java | 18 +- tool/src/main/java/migt/Check.java | 235 ++- tool/src/main/java/migt/DecodeOperation.java | 164 +- .../main/java/migt/DecodeOperation_API.java | 10 +- tool/src/main/java/migt/EditOperation.java | 173 +- tool/src/main/java/migt/ExecuteActives.java | 6 +- tool/src/main/java/migt/ExecutePassives.java | 4 +- tool/src/main/java/migt/ExecuteTrack.java | 18 +- tool/src/main/java/migt/GUI.java | 20 +- tool/src/main/java/migt/HTTPReqRes.java | 36 + tool/src/main/java/migt/MessageOperation.java | 105 +- tool/src/main/java/migt/MessageType.java | 2 +- tool/src/main/java/migt/Operation.java | 151 +- tool/src/main/java/migt/SessionOperation.java | 220 ++- .../main/java/migt/SessionTrackAction.java | 16 +- tool/src/main/java/migt/Test.java | 41 +- tool/src/main/java/migt/Tools.java | 820 ++++++++-- tool/src/main/java/migt/Utils.java | 1404 ----------------- tool/src/test/java/Checks_Test.java | 2 +- tool/src/test/java/DecodeOperation_Test.java | 7 +- tool/src/test/java/GUI_Test.java | 5 +- tool/src/test/java/JWT_Test.java | 10 - .../test/java/SessionTrackAction_Test.java | 12 +- tool/src/test/java/Utils_Test.java | 14 +- 26 files changed, 1711 insertions(+), 1789 deletions(-) delete mode 100644 tool/src/main/java/migt/Utils.java diff --git a/doc/language.md b/doc/language.md index e8a3c7a..335234b 100644 --- a/doc/language.md +++ b/doc/language.md @@ -489,15 +489,15 @@ The Checks tag is a list of Check elements, which can be defined with: - `in` says were to check the given parameter, can be _head_, _body_, _url_ - `check` checks if the given string is present in the specified message section - `check param` specifies the name of the parameter to be checked, depending on the section choosed, the tool will search for the parameter using a pattern. (for the url, it will search for a query parameter, for the head, it will search for a head parameter) +- `check regex` specify a regex that checks the selected content by matching it. - The actual check on the value, which are self explanatory. (if none of these are specified, the check will only check if the given parameter is present) - `is` - `not is` - `contains` - `not contains` - `is present` specifying true or false, to check whether is present or not -- `regex` specify a regex that checks the selected content by matching it. -Note that you can use `regex` OR (`check` OR `check param`). If you use the `check` tag, you can use all the other tags to verify the value, otherwise, if you use `check param` you can just use `is present`. +Note that you can use `check regex` OR `check` OR `check param`. If you use the `check` or `check param` tag, you can use all the other tags to verify the value, otherwise, if you use `check regex` you can just use `is present`. In passive tests the checks's result are intended as the entire test result, so all the checks has to pass to have a successfull test. @@ -864,3 +864,4 @@ Examples:
- Removed `raw header` `raw payload` `raw signature` from `jwt from` tag in Decode Operation - Added supprot of regex in checks (in future they will substitute existing regex) - Remove support for hardcoded standard message types such as oauth request and oauth response +- Removed support for hardcoded identification of OAuth flow \ No newline at end of file diff --git a/tool/.idea/compiler.xml b/tool/.idea/compiler.xml index 6465c9d..2c58695 100644 --- a/tool/.idea/compiler.xml +++ b/tool/.idea/compiler.xml @@ -6,7 +6,7 @@ - + diff --git a/tool/src/main/java/migt/BurpExtender.java b/tool/src/main/java/migt/BurpExtender.java index 3cde98b..c39ef0f 100644 --- a/tool/src/main/java/migt/BurpExtender.java +++ b/tool/src/main/java/migt/BurpExtender.java @@ -13,7 +13,7 @@ import java.util.regex.PatternSyntaxException; import static migt.Tools.executeDecodeOps; -import static migt.Utils.getVariableByName; +import static migt.Tools.getVariableByName; /** * Main class executed by Burp @@ -232,7 +232,7 @@ public void processProxyMessage(boolean messageIsRequest, IInterceptedProxyMessa if (matchMessage) { processMatchedMsg(msg_type, messageInfo); if (mainPane.act_active_op.then != null & - mainPane.act_active_op.then == Utils.Then.DROP) { + mainPane.act_active_op.then == Operation.Then.DROP) { message.setInterceptAction(IInterceptedProxyMessage.ACTION_DROP); } } @@ -424,7 +424,7 @@ public Operation executeMessageOps(Operation op, byte[] new_message; try { - if (mop.type == Utils.MessageOpType.GENERATE_POC) { + if (mop.type == MessageOperation.MessageOpType.GENERATE_POC) { if (!isRequest) { throw new ParsingException("Invalid POC generation, message should be a request"); } @@ -433,7 +433,7 @@ public Operation executeMessageOps(Operation op, continue; // other templates not supported yet } - String poc = Utils.generate_CSRF_POC(messageInfo, helpers); + String poc = Tools.generate_CSRF_POC(messageInfo, helpers); try { File myObj = new File(mop.output_path); @@ -527,7 +527,7 @@ public Operation executeMessageOps(Operation op, break; case EDIT: - op.processed_message = Utils.editMessageParam( + op.processed_message = Tools.editMessageParam( helpers, mop.what, mop.from, @@ -538,7 +538,7 @@ public Operation executeMessageOps(Operation op, break; case EDIT_REGEX: - op.processed_message = Utils.editMessage( + op.processed_message = Tools.editMessage( helpers, mop.what, mop, @@ -594,7 +594,7 @@ public Operation executeMessageOps(Operation op, switch (mop.from) { case HEAD: { String value = ""; - if (mop.action == Utils.MessageOperationActions.SAVE) { + if (mop.action == MessageOperation.MessageOperationActions.SAVE) { value = messageInfo.getHeadParam(isRequest, mop.what).trim(); } else { List headers = messageInfo.getHeaders(isRequest); @@ -642,7 +642,7 @@ public Operation executeMessageOps(Operation op, } String header_0 = messageInfo.getUrlHeader(); - pattern = mop.action == Utils.MessageOperationActions.SAVE ? + pattern = mop.action == MessageOperation.MessageOperationActions.SAVE ? Pattern.compile(mop.what + "=[^& ]*(?=(&| ))") : Pattern.compile(mop.what); @@ -651,7 +651,7 @@ public Operation executeMessageOps(Operation op, if (matcher.find()) { String matched = matcher.group(); - value = mop.action == Utils.MessageOperationActions.SAVE ? + value = mop.action == MessageOperation.MessageOperationActions.SAVE ? matched.split("=")[1] : matched; diff --git a/tool/src/main/java/migt/Check.java b/tool/src/main/java/migt/Check.java index 06e6d59..97f17fc 100644 --- a/tool/src/main/java/migt/Check.java +++ b/tool/src/main/java/migt/Check.java @@ -4,15 +4,18 @@ import burp.IRequestInfo; import burp.IResponseInfo; import com.jayway.jsonpath.JsonPath; +import org.json.JSONArray; import org.json.JSONObject; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static migt.Utils.CheckOps.IS_NOT_PRESENT; +import static migt.Check.CheckOps.IS_NOT_PRESENT; /** * Check Object class. This object is used in Operations to check that a parameter or some text is in as specified. @@ -21,15 +24,15 @@ */ public class Check extends Module { String what; // what to search - Utils.CheckOps op; // the check operations - Utils.CheckIn in; // the section over which to search + CheckOps op; // the check operations + CheckIn in; // the section over which to search String op_val; - boolean isParamCheck = false; // specifies if what is declared in what is a parameter name - - Utils.ContentType contentType; // The content on which the check should work on + List value_list; + boolean isParamCheck; // specifies if what is declared in what is a parameter name + String regex; public Check() { - + init(); } /** @@ -39,60 +42,78 @@ public Check() { * @throws ParsingException */ public Check(JSONObject json_check) throws ParsingException { + init(); Iterator keys = json_check.keys(); while (keys.hasNext()) { String key = keys.next(); switch (key) { case "in": - if (key.equals("in")) { - this.in = Utils.CheckIn.fromString(json_check.getString("in")); - } + this.in = CheckIn.fromString(json_check.getString("in")); + break; case "check param": - if (key.equals("check param")) { - this.isParamCheck = true; - this.setWhat(json_check.getString("check param")); - break; - } + this.isParamCheck = true; + this.setWhat(json_check.getString("check param")); + break; case "check": - if (key.equals("check")) { - this.setWhat(json_check.getString("check")); - break; - } + this.setWhat(json_check.getString("check")); + break; + case "check regex": + regex = json_check.getString("check regex"); + break; case "is": - if (key.equals("is")) { - this.setOp(Utils.CheckOps.IS); - this.op_val = json_check.getString("is"); - break; - } + this.setOp(CheckOps.IS); + this.op_val = json_check.getString("is"); + break; case "is not": - if (key.equals("is not")) { - this.setOp(Utils.CheckOps.IS_NOT); - this.op_val = json_check.getString("is not"); - break; - } + this.setOp(CheckOps.IS_NOT); + this.op_val = json_check.getString("is not"); + break; case "contains": - if (key.equals("contains")) { - this.setOp(Utils.CheckOps.CONTAINS); - this.op_val = json_check.getString("contains"); - break; - } + this.setOp(CheckOps.CONTAINS); + this.op_val = json_check.getString("contains"); + break; case "not contains": - if (key.equals("not contains")) { - this.setOp(Utils.CheckOps.NOT_CONTAINS); - this.op_val = json_check.getString("not contains"); - break; - } + this.setOp(CheckOps.NOT_CONTAINS); + this.op_val = json_check.getString("not contains"); + break; case "is present": - if (key.equals("is present")) { - this.op = json_check.getBoolean("is present") ? Utils.CheckOps.IS_PRESENT : - IS_NOT_PRESENT; - this.op_val = json_check.getBoolean("is present") ? - "is present" : "is not present"; + this.op = json_check.getBoolean("is present") ? CheckOps.IS_PRESENT : + IS_NOT_PRESENT; + this.op_val = json_check.getBoolean("is present") ? + "is present" : "is not present"; + break; + case "is in": + this.op = CheckOps.IS_IN; + JSONArray jsonArr = json_check.getJSONArray("is in"); + Iterator it = jsonArr.iterator(); + + while (it.hasNext()) { + String act_enc = (String) it.next(); + value_list.add(act_enc); + } + break; + case "is not in": + this.op = CheckOps.IS_NOT_IN; + JSONArray jsonArr2 = json_check.getJSONArray("is not in"); + Iterator it2 = jsonArr2.iterator(); + + while (it2.hasNext()) { + String act_enc = (String) it2.next(); + value_list.add(act_enc); } + break; } } } + public void init() { + what = ""; + op_val = ""; + isParamCheck = false; + regex = ""; + value_list = new ArrayList<>(); + } + public void loader(DecodeOperation_API api) { this.imported_api = api; } @@ -117,6 +138,7 @@ private boolean execute_http(HTTPReqRes message, if (this.in == null) { throw new ParsingException("from tag in checks is null"); } + switch (this.in) { case URL: if (!isRequest) { @@ -147,9 +169,14 @@ private boolean execute_http(HTTPReqRes message, return false; } + // if a regex is present, execute it + if (!regex.equals("")) { + return execute_regex(msg_str); + } + if (this.isParamCheck) { try { - Pattern p = this.in == Utils.CheckIn.URL ? + Pattern p = this.in == CheckIn.URL ? Pattern.compile("(?<=[?&]" + this.what + "=)[^\\n&]*") : Pattern.compile("(?<=" + this.what + ":\\s?)[^\\n]*"); Matcher m = p.matcher(msg_str); @@ -191,6 +218,10 @@ private boolean execute_http(HTTPReqRes message, return true; // if it gets to this, the searched param is already found case IS_NOT_PRESENT: return false; + case IS_IN: + return value_list.contains(val); // TODO check + case IS_NOT_IN: + return !value_list.contains(val); } } catch (ArrayIndexOutOfBoundsException e) { //e.printStackTrace(); @@ -244,6 +275,11 @@ private boolean execute_json() throws ParsingException { } } + // if a regex is present, execute it + if (!regex.equals("")) { + return execute_regex(j); + } + String found = ""; // https://github.com/json-path/JsonPath try { @@ -272,6 +308,10 @@ private boolean execute_json() throws ParsingException { return !found.equals(""); case IS_NOT_PRESENT: return found.equals(""); + case IS_IN: + return value_list.contains(found); + case IS_NOT_IN: + return !value_list.contains(found); } return false; @@ -312,7 +352,7 @@ public void setWhat(String what) { this.what = what; } - public void setOp(Utils.CheckOps op) { + public void setOp(CheckOps op) { this.op = op; } @@ -320,4 +360,107 @@ public void setOp(Utils.CheckOps op) { public String toString() { return "check: " + what + (op == null ? "" : " " + op + ": " + op_val); } + + /** + * Executes the regex of the check against the given input, and returns true if the regex found something. + * + * @param input the input text to check + * @return true if the regex matches, false otherwise + */ + private boolean execute_regex(String input) { + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(input); + applicable = true; + + String val = ""; + if (m.find()) { + val = m.group(); + } else { + return false; + } + // TODO: add is, isnot, .. ? + + return true; + } + + /** + * enum containing all the possible check operations + */ + public enum CheckOps { + IS, + IS_NOT, + CONTAINS, + NOT_CONTAINS, + IS_PRESENT, + IS_NOT_PRESENT, + IS_IN, + IS_NOT_IN; + + /** + * Function that given a String, returns the corresponding CheckOps enum's value + * + * @param input the input string + * @return the CheckOps enum value + * @throws ParsingException if the input string does not correspond to any of the possible check operations + */ + public static CheckOps fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "is": + return IS; + case "is not": + return IS_NOT; + case "contains": + return CONTAINS; + case "not contains": + return NOT_CONTAINS; + case "is in": + return IS_IN; + case "is not in": + return IS_NOT_IN; + default: + throw new ParsingException("invalid check operation"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * Used in the Check operation, to specify where is the content to check. + */ + public enum CheckIn { + // standard message + HEAD, + BODY, + URL, + // jwt + JWT_HEADER, + JWT_PAYLOAD, + JWT_SIGNATURE; + + public static CheckIn fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "head": + return HEAD; + case "body": + return BODY; + case "url": + return URL; + case "header": + return JWT_HEADER; + case "payload": + return JWT_PAYLOAD; + case "signature": + return JWT_SIGNATURE; + default: + throw new ParsingException("invalid in '" + input + "' for check"); + } + } else { + throw new NullPointerException(); + } + } + } } diff --git a/tool/src/main/java/migt/DecodeOperation.java b/tool/src/main/java/migt/DecodeOperation.java index 5296324..cf795fa 100644 --- a/tool/src/main/java/migt/DecodeOperation.java +++ b/tool/src/main/java/migt/DecodeOperation.java @@ -23,9 +23,9 @@ public class DecodeOperation extends Module { public String decoded_content; // the decoded content public String decode_target; // aka decode_param how to decode the raw content - public Utils.DecodeOperationFrom from; // where the raw content is. Depending on the containing module, can be other things - public List encodings; // the list of encoding to decode and rencode - public Utils.DecodeOpType type; // the type of the decoded param (used only to edit its content) + public DecodeOperationFrom from; // where the raw content is. Depending on the containing module, can be other things + public List encodings; // the list of encoding to decode and rencode + public DecodeOpType type; // the type of the decoded param (used only to edit its content) public List checks; // the list of checks to be executed public List decodeOperations; // a list of decode operations to execute them recursevly public List editOperations; // a list of edit operations @@ -52,7 +52,7 @@ public DecodeOperation(JSONObject decode_op_json) throws ParsingException { switch (key) { case "type": - type = Utils.DecodeOpType.fromString(decode_op_json.getString("type")); + type = DecodeOpType.fromString(decode_op_json.getString("type")); break; case "decode param": decode_target = decode_op_json.getString("decode param"); @@ -64,12 +64,12 @@ public DecodeOperation(JSONObject decode_op_json) throws ParsingException { while (it.hasNext()) { String act_enc = (String) it.next(); this.encodings.add( - Utils.Encoding.fromString(act_enc)); + Encoding.fromString(act_enc)); } break; case "from": String f = decode_op_json.getString("from"); - from = Utils.DecodeOperationFrom.fromString(f); + from = DecodeOperationFrom.fromString(f); break; case "decode operations": // Recursion goes brr @@ -81,10 +81,10 @@ public DecodeOperation(JSONObject decode_op_json) throws ParsingException { } break; case "checks": - checks = Utils.parseChecksFromJSON(decode_op_json.getJSONArray("checks")); + checks = Tools.parseChecksFromJSON(decode_op_json.getJSONArray("checks")); break; case "edits": - editOperations = Utils.parseEditsFromJSON(decode_op_json.getJSONArray("edits")); + editOperations = Tools.parseEditsFromJSON(decode_op_json.getJSONArray("edits")); break; } } @@ -104,8 +104,8 @@ public DecodeOperation(JSONObject decode_op_json) throws ParsingException { * @throws ParsingException If problems are encountered during decoding */ public static String decodeParam(IExtensionHelpers helpers, - Utils.DecodeOperationFrom ms, - List encodings, + DecodeOperationFrom ms, + List encodings, HTTPReqRes messageInfo, Boolean isRequest, String decode_param) throws ParsingException { @@ -125,7 +125,7 @@ public static String decodeParam(IExtensionHelpers helpers, break; } - decoded_param = Utils.removeNewline(decoded_param); + decoded_param = Tools.removeNewline(decoded_param); return decoded_param; } @@ -140,7 +140,7 @@ public static String decodeParam(IExtensionHelpers helpers, * @return the decoded string * @throws ParsingException if the decoding fails */ - public static String decode(List encodings, String encoded, IExtensionHelpers helpers) throws ParsingException { + public static String decode(List encodings, String encoded, IExtensionHelpers helpers) throws ParsingException { // TODO: remove dependency from helpers String actual = encoded; byte[] actual_b = null; @@ -150,7 +150,7 @@ public static String decode(List encodings, String encoded, IExt return ""; } - for (Utils.Encoding e : encodings) { + for (Encoding e : encodings) { switch (e) { case BASE64: if (isActualString) { @@ -230,11 +230,11 @@ public static String decode(List encodings, String encoded, IExt * @param decoded the string to be encoded * @return the encoded string */ - public static String encode(List encodings, String decoded, IExtensionHelpers helpers) { + public static String encode(List encodings, String decoded, IExtensionHelpers helpers) { String actual = decoded; byte[] actual_b = null; boolean isActualString = true; - for (Utils.Encoding e : encodings) { + for (Encoding e : encodings) { switch (e) { case BASE64: @@ -350,7 +350,7 @@ public void init() { encodings = new ArrayList<>(); decodeOperations = new ArrayList<>(); what = ""; - type = Utils.DecodeOpType.NONE; + type = DecodeOpType.NONE; editOperations = new ArrayList<>(); } @@ -360,6 +360,24 @@ public DecodeOperation_API getAPI() { return (DecodeOperation_API) api; } + public void setAPI(DecodeOperation_API dop_api) { + this.api = dop_api; + // assign values returned from the api + switch (type) { + case JWT: + this.jwt.header = dop_api.jwt_header; + this.jwt.payload = dop_api.jwt_payload; + this.jwt.signature = dop_api.jwt_signature; + break; + case NONE: + this.decoded_content = dop_api.txt; + break; + case XML: + this.decoded_content = dop_api.xml; + break; + } + } + /** * Loads an Operation API * @@ -395,7 +413,7 @@ public Operation_API exporter() throws ParsingException { Collections.reverse(encodings); // Set the right order for encoding String encoded = encode(encodings, decoded_content, helpers); - Utils.editMessageParam( + Tools.editMessageParam( helpers, decode_target, from, @@ -425,7 +443,7 @@ public void execute(GUI mainPane) throws ParsingException { decode_target); // If type is jwt, parse - if (Objects.requireNonNull(type) == Utils.DecodeOpType.JWT) { + if (Objects.requireNonNull(type) == DecodeOpType.JWT) { jwt = new JWT(); jwt.parse(decoded_content); @@ -459,7 +477,7 @@ public void execute(GUI mainPane) throws ParsingException { // execute edit operations if (editOperations.size() > 0) { - executeEditOps(this, helpers, mainPane); + executeEditOps(this, mainPane); } // executes recursive decode operations @@ -473,7 +491,7 @@ public void execute(GUI mainPane) throws ParsingException { } // Rebuild JWT before encoding it - if (Objects.requireNonNull(type) == Utils.DecodeOpType.JWT) { + if (Objects.requireNonNull(type) == DecodeOpType.JWT) { decoded_content = jwt.build(); } applicable = true; @@ -497,21 +515,97 @@ public boolean executeChecks() throws ParsingException { return true; } - public void setAPI(DecodeOperation_API dop_api) { - this.api = dop_api; - // assign values returned from the api - switch (type) { - case JWT: - this.jwt.header = dop_api.jwt_header; - this.jwt.payload = dop_api.jwt_payload; - this.jwt.signature = dop_api.jwt_signature; - break; - case NONE: - this.decoded_content = dop_api.txt; - break; - case XML: - this.decoded_content = dop_api.xml; - break; + /** + * Used in decode operation to specify where to search for the content to decode + */ + public enum DecodeOperationFrom { + // standard message + HEAD, + BODY, + URL, + // jwt + JWT_HEADER, + JWT_PAYLOAD, + JWT_SIGNATURE; + + public static DecodeOperationFrom fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "head": + return HEAD; + case "body": + return BODY; + case "url": + return URL; + case "jwt header": + return JWT_HEADER; + case "jwt payload": + return JWT_PAYLOAD; + case "jwt signature": + return JWT_SIGNATURE; + default: + throw new ParsingException("invalid decode operation from '" + input + "'"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * The possible encodings to be used + */ + public enum Encoding { + BASE64, + URL, + DEFLATE; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static Encoding fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "base64": + return BASE64; + case "url": + return URL; + case "deflate": + return DEFLATE; + default: + throw new ParsingException("invalid encoding"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * Used to specify the type of decoded content, only when that content has to be edited. + */ + public enum DecodeOpType { + JWT, + NONE, + XML; + + public static DecodeOpType fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "jwt": + return JWT; + case "xml": + return XML; + default: + throw new ParsingException("invalid message Op Type"); + } + } else { + throw new NullPointerException(); + } } } } diff --git a/tool/src/main/java/migt/DecodeOperation_API.java b/tool/src/main/java/migt/DecodeOperation_API.java index cbe1a28..4032e79 100644 --- a/tool/src/main/java/migt/DecodeOperation_API.java +++ b/tool/src/main/java/migt/DecodeOperation_API.java @@ -1,7 +1,7 @@ package migt; public class DecodeOperation_API extends API { - public Utils.DecodeOpType type; // the type of the decoded param + public DecodeOperation.DecodeOpType type; // the type of the decoded param public String jwt_header; public String jwt_payload; @@ -31,7 +31,7 @@ public DecodeOperation_API(DecodeOperation dop) { } } - public String getDecodedContent(Utils.DecodeOperationFrom dopfrom) throws ParsingException { + public String getDecodedContent(DecodeOperation.DecodeOperationFrom dopfrom) throws ParsingException { switch (dopfrom) { case HEAD: throw new ParsingException("cannot decode from header in a recursive decode"); @@ -40,17 +40,17 @@ public String getDecodedContent(Utils.DecodeOperationFrom dopfrom) throws Parsin case URL: throw new ParsingException("cannot decode from url in a recursive decode"); case JWT_HEADER: - if (type != Utils.DecodeOpType.JWT) + if (type != DecodeOperation.DecodeOpType.JWT) throw new ParsingException("cannot decode in a jwt header if previous decode was not a jwt"); return jwt_header; case JWT_PAYLOAD: - if (type != Utils.DecodeOpType.JWT) + if (type != DecodeOperation.DecodeOpType.JWT) throw new ParsingException("cannot decode in a jwt payload if previous decode was not a jwt"); return jwt_payload; case JWT_SIGNATURE: - if (type != Utils.DecodeOpType.JWT) + if (type != DecodeOperation.DecodeOpType.JWT) throw new ParsingException("cannot decode in a jwt signature if previous decode was not a jwt"); return jwt_signature; default: diff --git a/tool/src/main/java/migt/EditOperation.java b/tool/src/main/java/migt/EditOperation.java index 99e4a9f..4ac74e1 100644 --- a/tool/src/main/java/migt/EditOperation.java +++ b/tool/src/main/java/migt/EditOperation.java @@ -10,11 +10,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static migt.Utils.getVariableByName; +import static migt.Tools.getVariableByName; public class EditOperation extends Module { // XML - Utils.XmlAction xml_action; + XmlAction xml_action; String xml_action_name; String xml_tag; String xml_attr; @@ -29,14 +29,14 @@ public class EditOperation extends Module { String save_as; // say the name of the parameter to save the value // JWT - Utils.Jwt_section jwt_section; - Utils.Jwt_action jwt_action; + Jwt_section jwt_section; + Jwt_action jwt_action; boolean sign; String what; // TXT - Utils.TxtAction txt_action; + TxtAction txt_action; String txt_action_name; public EditOperation(JSONObject eop_json) throws ParsingException { @@ -57,35 +57,35 @@ public EditOperation(JSONObject eop_json) throws ParsingException { value = eop_json.getString("value"); break; case "add tag": - xml_action = Utils.XmlAction.ADD_TAG; + xml_action = XmlAction.ADD_TAG; xml_action_name = eop_json.getString(key); break; case "add attribute": - xml_action = Utils.XmlAction.ADD_ATTR; + xml_action = XmlAction.ADD_ATTR; xml_action_name = eop_json.getString(key); break; case "edit tag": - xml_action = Utils.XmlAction.EDIT_TAG; + xml_action = XmlAction.EDIT_TAG; xml_action_name = eop_json.getString(key); break; case "edit attribute": - xml_action = Utils.XmlAction.EDIT_ATTR; + xml_action = XmlAction.EDIT_ATTR; xml_action_name = eop_json.getString(key); break; case "remove tag": - xml_action = Utils.XmlAction.REMOVE_TAG; + xml_action = XmlAction.REMOVE_TAG; xml_action_name = eop_json.getString(key); break; case "remove attribute": - xml_action = Utils.XmlAction.REMOVE_ATTR; + xml_action = XmlAction.REMOVE_ATTR; xml_action_name = eop_json.getString(key); break; case "save tag": - xml_action = Utils.XmlAction.SAVE_TAG; + xml_action = XmlAction.SAVE_TAG; xml_action_name = eop_json.getString(key); break; case "save attribute": - xml_action = Utils.XmlAction.SAVE_ATTR; + xml_action = XmlAction.SAVE_ATTR; xml_action_name = eop_json.getString(key); break; case "self-sign": @@ -105,23 +105,23 @@ public EditOperation(JSONObject eop_json) throws ParsingException { break; // JWT case "jwt from": - jwt_section = Utils.Jwt_section.getFromString( + jwt_section = Jwt_section.getFromString( eop_json.getString("jwt from")); break; case "jwt remove": - jwt_action = Utils.Jwt_action.REMOVE; + jwt_action = Jwt_action.REMOVE; what = eop_json.getString("jwt remove"); break; case "jwt edit": - jwt_action = Utils.Jwt_action.EDIT; + jwt_action = Jwt_action.EDIT; what = eop_json.getString("jwt edit"); break; case "jwt add": - jwt_action = Utils.Jwt_action.ADD; + jwt_action = Jwt_action.ADD; what = eop_json.getString("jwt add"); break; case "jwt save": - jwt_action = Utils.Jwt_action.SAVE; + jwt_action = Jwt_action.SAVE; what = eop_json.getString("jwt save"); break; case "jwt sign": @@ -129,19 +129,19 @@ public EditOperation(JSONObject eop_json) throws ParsingException { break; case "txt remove": - txt_action = Utils.TxtAction.REMOVE; + txt_action = TxtAction.REMOVE; txt_action_name = eop_json.getString("txt remove"); break; case "txt edit": - txt_action = Utils.TxtAction.EDIT; + txt_action = TxtAction.EDIT; txt_action_name = eop_json.getString("txt edit"); break; case "txt add": - txt_action = Utils.TxtAction.ADD; + txt_action = TxtAction.ADD; txt_action_name = eop_json.getString("txt add"); break; case "txt save": - txt_action = Utils.TxtAction.SAVE; + txt_action = TxtAction.SAVE; txt_action_name = eop_json.getString("txt save"); break; } @@ -291,16 +291,16 @@ public void execute(GUI mainPane) throws ParsingException { try { switch (jwt_section) { case HEADER: - tmp_imported_api.jwt_header = Utils.editJson( + tmp_imported_api.jwt_header = Tools.editJson( jwt_action, tmp_imported_api.jwt_header, what, mainPane, save_as, value); break; case PAYLOAD: // TODO: pass newvalue - tmp_imported_api.jwt_payload = Utils.editJson( + tmp_imported_api.jwt_payload = Tools.editJson( jwt_action, tmp_imported_api.jwt_payload, what, mainPane, save_as, value); break; case SIGNATURE: - tmp_imported_api.jwt_signature = Utils.editJson( + tmp_imported_api.jwt_signature = Tools.editJson( jwt_action, tmp_imported_api.jwt_signature, what, mainPane, save_as, value); break; } @@ -360,4 +360,127 @@ public void execute(GUI mainPane) throws ParsingException { imported_api = tmp_imported_api; } } + + /** + * The possible XML actions are the ones described in this enum + */ + public enum XmlAction { + ADD_TAG, + ADD_ATTR, + EDIT_TAG, + EDIT_ATTR, + REMOVE_TAG, + REMOVE_ATTR, + SAVE_TAG, + SAVE_ATTR; + + /** + * From a string get the corresponding value + * + * @param input the input string + * @return the enum value + * @throws ParsingException if the string does not correspond to any of the values + */ + public static XmlAction fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "add tag": + return ADD_TAG; + case "add attribute": + return ADD_ATTR; + case "edit tag": + return EDIT_TAG; + case "edit attribute": + return EDIT_ATTR; + case "remove tag": + return REMOVE_TAG; + case "remove attribute": + return REMOVE_ATTR; + case "save tag": + return SAVE_TAG; + case "save attribute": + return SAVE_ATTR; + default: + throw new ParsingException("invalid xml action"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * Defines the possible actions to be done on a decoded parameter interpreted as plain text + */ + public enum TxtAction { + REMOVE, + EDIT, + ADD, + SAVE; + + /** + * From a string get the corresponding value + * + * @param input the input string + * @return the enum value + * @throws ParsingException if the string does not correspond to any of the values + */ + public static TxtAction fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "txt remove": + return REMOVE; + case "txt edit": + return EDIT; + case "txt add": + return ADD; + case "txt save": + return SAVE; + default: + throw new ParsingException("invalid xml action"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * Defines the possible actions to be done on a JWT token + */ + public enum Jwt_action { + REMOVE, + EDIT, + ADD, + SAVE + } + + /** + * Defines the possible JWT token sections + */ + public enum Jwt_section { + HEADER, + PAYLOAD, + SIGNATURE; + + /** + * Get the JWT section enum value from a string + * + * @param s the string to parse + * @return the enum value + * @throws ParsingException if the string is invalid + */ + public static Jwt_section getFromString(String s) throws ParsingException { + switch (s) { + case "header": + return HEADER; + case "payload": + return PAYLOAD; + case "signature": + return SIGNATURE; + default: + throw new ParsingException("Invalid jwt section"); + } + } + } } diff --git a/tool/src/main/java/migt/ExecuteActives.java b/tool/src/main/java/migt/ExecuteActives.java index de5befc..1245569 100644 --- a/tool/src/main/java/migt/ExecuteActives.java +++ b/tool/src/main/java/migt/ExecuteActives.java @@ -79,13 +79,13 @@ public void onExecuteDone(boolean errors, String current_url, String sessionName if (actual_test.resultSession.equals("") || actual_test.resultSession.equals(sessionName)) { - if (actual_test.result == Utils.ResultType.CORRECT_FLOW) { + if (actual_test.result == Test.ResultType.CORRECT_FLOW) { if (errors || current_url.contains("error")) { actual_test.success = false; } - } else if (actual_test.result == Utils.ResultType.INCORRECT_FLOW) { + } else if (actual_test.result == Test.ResultType.INCORRECT_FLOW) { actual_test.success = errors; // Difficult to read - } else if (actual_test.result == Utils.ResultType.ASSERT_ONLY) { + } else if (actual_test.result == Test.ResultType.ASSERT_ONLY) { actual_test.success = true; //at this point, all the asserts have been executed, and if they failed // they already returned a false result diff --git a/tool/src/main/java/migt/ExecutePassives.java b/tool/src/main/java/migt/ExecutePassives.java index 1ff1654..c87d0cd 100644 --- a/tool/src/main/java/migt/ExecutePassives.java +++ b/tool/src/main/java/migt/ExecutePassives.java @@ -61,7 +61,7 @@ public void run() { HashMap> batch = null; try { - batch = Utils.batchPassivesFromSession(passives); + batch = Tools.batchPassivesFromSession(passives); } catch (ParsingException e) { e.printStackTrace(); //lblOutput.setText(e.getMessage()); @@ -113,7 +113,7 @@ public void run() { // TODO: Remove used session executedSession = null; } - passives = Utils.debatchPassive(batch); + passives = Tools.debatchPassive(batch); listener.onExecuteDone(passives); } diff --git a/tool/src/main/java/migt/ExecuteTrack.java b/tool/src/main/java/migt/ExecuteTrack.java index a2b8462..4094273 100644 --- a/tool/src/main/java/migt/ExecuteTrack.java +++ b/tool/src/main/java/migt/ExecuteTrack.java @@ -132,10 +132,10 @@ public void run() { } catch (WebDriverException e) { } - if (track.getTrack().get(i).action == Utils.SessAction.CLICK) { + if (track.getTrack().get(i).action == SessionOperation.SessAction.CLICK) { last_click = track.getTrack().get(i); } - if (track.getTrack().get(i).action == Utils.SessAction.OPEN) { + if (track.getTrack().get(i).action == SessionOperation.SessAction.OPEN) { last_open = track.getTrack().get(i); } listener.onNextSessionAction(last_action, last_open, last_click, last_url, sessionName); @@ -236,9 +236,9 @@ public void run() { while (windows_checked != windows_count) { try { - boolean is_snapshot = action.action == Utils.SessAction.SNAPSHOT || - action.action == Utils.SessAction.DIFF || - action.action == Utils.SessAction.EQUALS; + boolean is_snapshot = action.action == SessionOperation.SessAction.SNAPSHOT || + action.action == SessionOperation.SessAction.DIFF || + action.action == SessionOperation.SessAction.EQUALS; By by = null; // Checks for the presence of a valid item to search @@ -262,7 +262,7 @@ public void run() { throw new ParsingException("invalid session track command"); } - if (action.action == Utils.SessAction.ASSERT_VISIBLE) { + if (action.action == SessionOperation.SessAction.ASSERT_VISIBLE) { new WebDriverWait(driver, Duration.ofSeconds(TIMEOUT)).until( ExpectedConditions.visibilityOfElementLocated(by)); } else if (is_snapshot) { @@ -291,8 +291,8 @@ public void run() { if (currentElement != null) break; } if (currentElement == null) { - if (action.action == Utils.SessAction.ASSERT_CLICKABLE - || action.action == Utils.SessAction.ASSERT_VISIBLE) { + if (action.action == SessionOperation.SessAction.ASSERT_CLICKABLE + || action.action == SessionOperation.SessAction.ASSERT_VISIBLE) { listener.onExecuteDone(false, sessionName); driver.close(); return; @@ -334,7 +334,7 @@ public void run() { String diff = currentElement.getScreenshotAs(OutputType.BASE64); File f2 = currentElement.getScreenshotAs(OutputType.FILE); f2.renameTo(new File("./diff.png")); - if (action.action == Utils.SessAction.DIFF) { + if (action.action == SessionOperation.SessAction.DIFF) { if (diff.equals(snapshot)) { listener.onExecuteDone(true, current_url, sessionName); driver.close(); diff --git a/tool/src/main/java/migt/GUI.java b/tool/src/main/java/migt/GUI.java index 0e6a2f4..5ac889b 100644 --- a/tool/src/main/java/migt/GUI.java +++ b/tool/src/main/java/migt/GUI.java @@ -1064,7 +1064,7 @@ private void readMsgDefFile() { tmp += myReader.nextLine(); } myReader.close(); - messageTypes = Utils.readMsgTypeFromJson(tmp); + messageTypes = Tools.readMsgTypeFromJson(tmp); } catch (ParsingException e) { lblOutput.setText("Invalid message type in message type definition file"); e.printStackTrace(); @@ -1073,9 +1073,9 @@ private void readMsgDefFile() { } } else { FileWriter w = new FileWriter(MSG_DEF_PATH); - w.write(Utils.getDefaultJSONMsgType()); + w.write(Tools.getDefaultJSONMsgType()); w.close(); - messageTypes = Utils.readMsgTypeFromJson(Utils.getDefaultJSONMsgType()); + messageTypes = Tools.readMsgTypeFromJson(Tools.getDefaultJSONMsgType()); } } catch (ParsingException e) { e.printStackTrace(); @@ -1129,7 +1129,7 @@ private void readConfigFile() { } } else { FileWriter w = new FileWriter(CONFIG_FILE_PATH); - w.write(Utils.getDefaultJSONConfig()); + w.write(Tools.getDefaultJSONConfig()); w.close(); } } catch (IOException e) { @@ -1173,7 +1173,7 @@ private void editConfigFile(String key, String value) { } } else { FileWriter w = new FileWriter(CONFIG_FILE_PATH); - w.write(Utils.getDefaultJSONConfig()); + w.write(Tools.getDefaultJSONConfig()); w.close(); } } catch (IOException e) { @@ -1344,6 +1344,7 @@ private void executeSuite() { public void onExecuteStart() { ACTIVE_ENABLED = false; act_active_op = new Operation(); + lblOutput.setText("Executing active tests"); } @Override @@ -1351,12 +1352,13 @@ public void onExecuteDone() { if (passives.size() == 0) { update_gui_test_results(); - lblOutput.setText("Passive Tests: " + lblOutput.setText("Done. Executed Passive Tests: " + (passives.isEmpty() ? 0 : passives.size()) + " - Active Tests: " + (testSuite.getTests().size() - (passives.isEmpty() ? 0 : passives.size()))); + } else { + lblOutput.setText("Executed Active tests, now doing passives"); } - lblOutput.setText("Executed Active tests, now doing passives"); synchronized (lock2) { active_ex_finished = true; } @@ -1479,13 +1481,13 @@ public boolean onWaitToStart() { @Override public void onExecuteStart() { - + lblOutput.setText("Executing passive tests"); } @Override public void onExecuteDone(List passives_test) { //TODO: Check if this is ok - lblOutput.setText("Passive Tests: " + lblOutput.setText("Done. Executed Passive Tests: " + (passives.isEmpty() ? 0 : passives.size()) + " - Active Tests: " + (testSuite.getTests().size() - (passives.isEmpty() ? 0 : passives.size()))); diff --git a/tool/src/main/java/migt/HTTPReqRes.java b/tool/src/main/java/migt/HTTPReqRes.java index f4d025d..3b209d2 100644 --- a/tool/src/main/java/migt/HTTPReqRes.java +++ b/tool/src/main/java/migt/HTTPReqRes.java @@ -459,4 +459,40 @@ public String getBodyRegex(Boolean isRequest, String param) { } return res; } + + /** + * An enum representing the possible message sections + */ + public enum MessageSection { + HEAD, + BODY, + URL, + RAW; + + /** + * Function that given a message section in form of String, returns the corresponding MessageSection enum value + * + * @param input the input string + * @return the MessageSection enum value + * @throws ParsingException if the input does not correspond to any of the possible messagesections + */ + public static MessageSection fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "head": + return HEAD; + case "body": + return BODY; + case "url": + return URL; + case "raw": + return RAW; + default: + throw new ParsingException("message section not valid"); + } + } else { + throw new NullPointerException(); + } + } + } } diff --git a/tool/src/main/java/migt/MessageOperation.java b/tool/src/main/java/migt/MessageOperation.java index b6e1959..7f1a58b 100644 --- a/tool/src/main/java/migt/MessageOperation.java +++ b/tool/src/main/java/migt/MessageOperation.java @@ -11,15 +11,15 @@ * @author Matteo Bitussi */ public class MessageOperation { - Utils.MessageSection from; + HTTPReqRes.MessageSection from; String what; String to; - Utils.MessageOperationActions action; + MessageOperationActions action; String save_as; // The name of the variable to save the parameter's value String use; String decode_param; - List encodings; - Utils.MessageOpType type; + List encodings; + MessageOpType type; // GENERATE POC String template; @@ -35,7 +35,7 @@ public MessageOperation() { this.use = ""; this.decode_param = ""; this.encodings = new ArrayList<>(); - this.type = Utils.MessageOpType.HTTP; + this.type = MessageOpType.HTTP; this.template = ""; this.output_path = ""; } @@ -47,7 +47,7 @@ public MessageOperation(JSONObject message_op_json) throws ParsingException { this.use = ""; this.decode_param = ""; this.encodings = new ArrayList<>(); - this.type = Utils.MessageOpType.HTTP; + this.type = MessageOpType.HTTP; this.template = ""; this.output_path = ""; @@ -57,41 +57,41 @@ public MessageOperation(JSONObject message_op_json) throws ParsingException { switch (key) { case "from": - from = Utils.MessageSection.fromString(message_op_json.getString("from")); + from = HTTPReqRes.MessageSection.fromString(message_op_json.getString("from")); break; case "remove parameter": what = message_op_json.getString("remove parameter"); - action = Utils.MessageOperationActions.REMOVE_PARAMETER; + action = MessageOperationActions.REMOVE_PARAMETER; break; case "remove match word": what = message_op_json.getString("remove match word"); - action = Utils.MessageOperationActions.REMOVE_MATCH_WORD; + action = MessageOperationActions.REMOVE_MATCH_WORD; break; case "edit": what = message_op_json.getString("edit"); - action = Utils.MessageOperationActions.EDIT; + action = MessageOperationActions.EDIT; break; case "edit regex": what = message_op_json.getString("edit regex"); - action = Utils.MessageOperationActions.EDIT_REGEX; + action = MessageOperationActions.EDIT_REGEX; break; case "in": to = message_op_json.getString("in"); break; case "add": what = message_op_json.getString("add"); - action = Utils.MessageOperationActions.ADD; + action = MessageOperationActions.ADD; break; case "this": to = message_op_json.getString("this"); break; case "save": what = message_op_json.getString("save"); - action = Utils.MessageOperationActions.SAVE; + action = MessageOperationActions.SAVE; break; case "save match": what = message_op_json.getString("save match"); - action = Utils.MessageOperationActions.SAVE_MATCH; + action = MessageOperationActions.SAVE_MATCH; break; case "as": save_as = message_op_json.getString("as"); @@ -100,7 +100,7 @@ public MessageOperation(JSONObject message_op_json) throws ParsingException { use = message_op_json.getString("use"); break; case "type": - type = Utils.MessageOpType.fromString( + type = MessageOpType.fromString( message_op_json.getString("type")); break; case "template": @@ -115,4 +115,79 @@ public MessageOperation(JSONObject message_op_json) throws ParsingException { } } } + + /** + * All the possible actions of a MessageOperation + */ + public enum MessageOperationActions { + REMOVE_PARAMETER, + REMOVE_MATCH_WORD, + EDIT, + EDIT_REGEX, + ADD, + SAVE, + SAVE_MATCH; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static MessageOperationActions fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "remove parameter": + return REMOVE_PARAMETER; + case "remove match word": + return REMOVE_MATCH_WORD; + case "edit": + return EDIT; + case "edit regex": + return EDIT_REGEX; + case "add": + return ADD; + case "save": + return SAVE; + case "save match": + return SAVE_MATCH; + default: + throw new ParsingException("invalid check operation"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * The possible types of messageOps + */ + public enum MessageOpType { + HTTP, + GENERATE_POC; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static MessageOpType fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "http": + return HTTP; + case "generate_poc": + return GENERATE_POC; + default: + throw new ParsingException("invalid message Op Type"); + } + } else { + throw new NullPointerException(); + } + } + } } diff --git a/tool/src/main/java/migt/MessageType.java b/tool/src/main/java/migt/MessageType.java index 9d4ed0f..050419d 100644 --- a/tool/src/main/java/migt/MessageType.java +++ b/tool/src/main/java/migt/MessageType.java @@ -13,7 +13,7 @@ public class MessageType implements Cloneable { Boolean isRequest; String regex; List checks; - Utils.MessageSection messageSection; + HTTPReqRes.MessageSection messageSection; String responseName; String requestName; diff --git a/tool/src/main/java/migt/Operation.java b/tool/src/main/java/migt/Operation.java index 3531506..14f3304 100644 --- a/tool/src/main/java/migt/Operation.java +++ b/tool/src/main/java/migt/Operation.java @@ -9,8 +9,8 @@ import java.util.Iterator; import java.util.List; -import static migt.Utils.buildStringWithVars; -import static migt.Utils.findParentDiv; +import static migt.Tools.buildStringWithVars; +import static migt.Tools.findParentDiv; /** * Class storing an Operation in a Test @@ -21,7 +21,7 @@ public class Operation extends Module { public List messageOerations; public String from_session; public String to_session; - public Utils.Then then; + public Then then; public String save_name; public int to_match; public int act_matched; @@ -30,12 +30,11 @@ public class Operation extends Module { public String replace_request_name; public String replace_response_name; public boolean isSessionOp = false; - public boolean isRegex = false; public List matchedMessages; public byte[] processed_message; public IHttpService processed_message_service; // null if it is not changed public String decode_param; - public List encodings; + public List encodings; public List log_messages; public List session_operations; // Decode operations @@ -43,15 +42,12 @@ public class Operation extends Module { // Session operation // API Operation_API api; - //boolean applicable = false; // if the operation can't find a matching message, is not applicable - //boolean result = true; // defalult true private List checks; private String messageType; - private String regex; - private Utils.MessageSection messageSection; - private Utils.Action action; + private HTTPReqRes.MessageSection messageSection; + private Action action; private String session; - private Utils.SessionAction sessionAction; + private SessionOperation.SessionAction sessionAction; /** * Instantiate an operation @@ -60,10 +56,19 @@ public Operation() { init(); } + /** + * Instantiate an Operation parsing a JSON object + * + * @param operation_json the operation defined in MIG-L as JSONObject + * @param isActive if the operation is used inside an active or passive test + * @param messageTypes All the message types imported + * @throws Exception + */ public Operation(JSONObject operation_json, boolean isActive, List messageTypes) throws Exception { init(); + if (!isActive) { if (operation_json.has("decode param")) { decode_param = operation_json.getString("decode param"); @@ -74,22 +79,17 @@ public Operation(JSONObject operation_json, while (it.hasNext()) { String act_enc = (String) it.next(); this.encodings.add( - Utils.Encoding.fromString(act_enc)); + DecodeOperation.Encoding.fromString(act_enc)); } } - if (operation_json.has("regex")) { - // regex version - isRegex = true; - setRegex(operation_json.getString("regex")); - setMessageSection(Utils.MessageSection.fromString(operation_json.getString("message section"))); - } else { + if (operation_json.has("checks")) { //non regex version JSONArray checks = operation_json.getJSONArray("checks"); if (operation_json.has("message section")) { - setMessageSection(Utils.MessageSection.fromString(operation_json.getString("message section"))); + setMessageSection(HTTPReqRes.MessageSection.fromString(operation_json.getString("message section"))); } - setChecks(Utils.parseChecksFromJSON(checks)); + setChecks(Tools.parseChecksFromJSON(checks)); } } else { // If the test is active @@ -116,7 +116,7 @@ public Operation(JSONObject operation_json, setAction(action); // if it is a validate - if (getAction() == Utils.Action.VALIDATE) { + if (getAction() == Action.VALIDATE) { // TODO: to remove match? if (operation_json.has("match")) { String toMatch = operation_json.getString("match"); @@ -125,20 +125,9 @@ public Operation(JSONObject operation_json, } else { to_match = 1; } - - if (operation_json.has("regex")) { - // regex version - isRegex = true; - setRegex(operation_json.getString("regex")); - setMessageSection( - Utils.MessageSection.fromString( - operation_json.getString("message section"))); - } else { - //non regex version - JSONArray checks = operation_json.getJSONArray("checks"); - - setChecks(Utils.parseChecksFromJSON(checks)); - } + //non regex version + JSONArray checks = operation_json.getJSONArray("checks"); + setChecks(Tools.parseChecksFromJSON(checks)); } if (operation_json.has("from session")) { @@ -148,7 +137,7 @@ public Operation(JSONObject operation_json, to_session = operation_json.getString("to session"); } if (operation_json.has("then")) { - then = Utils.Then.fromString(operation_json.getString("then")); + then = Then.fromString(operation_json.getString("then")); } if (operation_json.has("save")) { save_name = operation_json.getString("save"); @@ -162,7 +151,7 @@ public Operation(JSONObject operation_json, // Preconditions if (operation_json.has("preconditions")) { JSONArray checks = operation_json.getJSONArray("preconditions"); - preconditions = Utils.parseChecksFromJSON(checks); + preconditions = Tools.parseChecksFromJSON(checks); } // Message Operations @@ -208,7 +197,6 @@ private void init() { this.replace_response_name = ""; this.replace_request_name = ""; this.messageType = ""; - this.regex = ""; this.session = ""; this.decode_param = ""; this.processed_message_service = null; @@ -247,31 +235,24 @@ public void setChecks(List checks) { this.checks = checks; } - public String getRegex() { - return regex; - } - public void setRegex(String regex) { - this.regex = regex; - } - - public Utils.MessageSection getMessageSection() { + public HTTPReqRes.MessageSection getMessageSection() { return messageSection; } - public void setMessageSection(Utils.MessageSection messageSection) { + public void setMessageSection(HTTPReqRes.MessageSection messageSection) { this.messageSection = messageSection; } - public Utils.Action getAction() { + public Action getAction() { return action; } public void setAction(String action) throws ParsingException { - this.setAction(Utils.Action.fromString(action)); + this.setAction(Action.fromString(action)); } - public void setAction(Utils.Action action) { + public void setAction(Action action) { this.action = action; } @@ -283,15 +264,15 @@ public void setSession(String sessionName) { this.session = sessionName; } - public Utils.SessionAction getSessionAction() { + public SessionOperation.SessionAction getSessionAction() { return sessionAction; } public void setSessionAction(String sessionAction) throws ParsingException { - this.setSessionAction(Utils.SessionAction.fromString(sessionAction)); + this.setSessionAction(SessionOperation.SessionAction.fromString(sessionAction)); } - public void setSessionAction(Utils.SessionAction sessionAction) { + public void setSessionAction(SessionOperation.SessionAction sessionAction) { this.sessionAction = sessionAction; } @@ -445,6 +426,70 @@ public void setAPI(Operation_API api) { this.processed_message = api.message.build_message(api.is_request); } + public void execute() { + // TODO + } + + /** + * Enum containing all the possible Active operation actions + */ + public enum Action { + INTERCEPT, + VALIDATE; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static Action fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "intercept": + return INTERCEPT; + case "validate": + return VALIDATE; + default: + throw new ParsingException("invalid check operation"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * Enum that contains all the possible action to do after a message is received + */ + public enum Then { + FORWARD, + DROP; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static Then fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "forward": + return FORWARD; + case "drop": + return DROP; + default: + throw new ParsingException("invalid check operation"); + } + } else { + throw new NullPointerException(); + } + } + } + /** * Class to store the index and some information about matched messages (with regex or check) in an operation */ diff --git a/tool/src/main/java/migt/SessionOperation.java b/tool/src/main/java/migt/SessionOperation.java index 48b6446..07ad389 100644 --- a/tool/src/main/java/migt/SessionOperation.java +++ b/tool/src/main/java/migt/SessionOperation.java @@ -16,14 +16,14 @@ */ public class SessionOperation { public String from_session; - public Utils.SessOperationAction action; + public SessOperationAction action; public String what; public String as; public String at; public String to; // until to which ession action save public boolean is_from_included = false; public boolean is_to_included = false; - public Utils.SessOperationTarget target; + public SessOperationTarget target; public String mark_name; /** @@ -49,23 +49,23 @@ public static List parseFromJson(JSONObject act_operation) thr sop.from_session = act_session_op.getString("session"); break; case "save": - sop.action = Utils.SessOperationAction.SAVE; - sop.target = Utils.SessOperationTarget + sop.action = SessOperationAction.SAVE; + sop.target = SessOperationTarget .getFromString(act_session_op.getString("save")); break; case "as": sop.as = act_session_op.getString("as"); break; case "insert": - sop.action = Utils.SessOperationAction.INSERT; + sop.action = SessOperationAction.INSERT; sop.what = act_session_op.getString("insert"); break; case "at": sop.at = act_session_op.getString("at"); break; case "mark": - sop.action = Utils.SessOperationAction.MARKER; - sop.target = Utils.SessOperationTarget + sop.action = SessOperationAction.MARKER; + sop.target = SessOperationTarget .getFromString(act_session_op.getString("mark")); sop.mark_name = act_session_op.getString("name"); break; @@ -73,7 +73,7 @@ public static List parseFromJson(JSONObject act_operation) thr //Already processed in mark break; case "remove": - sop.action = Utils.SessOperationAction.REMOVE; + sop.action = SessOperationAction.REMOVE; if (sop.at == null || sop.at.length() == 0) { sop.at = act_session_op.getString("remove"); } @@ -138,4 +138,208 @@ public static List parseRange(String range) throws ParsingException { return l; } + + /** + * Enum containing all the possible session operation actions + */ + public enum SessionAction { + START, + PAUSE, + RESUME, + STOP, + CLEAR_COOKIES; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static SessionAction fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "start": + return START; + case "pause": + return PAUSE; + case "resume": + return RESUME; + case "stop": + return STOP; + case "clear cookies": + return CLEAR_COOKIES; + default: + throw new ParsingException("invalid Session action"); + } + } else { + throw new NullPointerException(); + } + } + } + + /** + * Defines the action of a session action + */ + public enum SessAction { + CLICK, + OPEN, + TYPE, + SNAPSHOT, + DIFF, + EQUALS, + WAIT, + SET_VAR, + CLEAR_COOKIES, + ASSERT_CLICKABLE, + ASSERT_NOT_CLICKABLE, + ASSERT_VISIBLE, + ASSERT_NOT_VISIBLE, + ASSERT_ELEM_CONTENT_IS, + ASSERT_ELEM_CONTENT_HAS, + ASSERT_ELEM_CLASS_IS, + ASSERT_ELEM_CLASS_HAS, + ASSERT_ELEM_HAS_ATTRIBUTE, + ASSERT_ELEM_NOT_HAS_ATTRIBUTE, + ALERT; + + /** + * Get a session action enum value from a string + * + * @param s the string + * @return the enum value + * @throws ParsingException if the string is invalid + */ + public static SessAction getFromString(String s) throws ParsingException { + switch (s) { + case "assert click": + case "click": + return CLICK; + case "open": + case "assert open": // just an alias of open + return OPEN; + case "type": + return TYPE; + case "snapshot": + return SNAPSHOT; + case "diff": + return DIFF; + case "equals": + return EQUALS; + case "wait": + return WAIT; + case "set var": + return SET_VAR; + case "clear cookies": + return CLEAR_COOKIES; + case "assert clickable": + return ASSERT_CLICKABLE; + case "assert not clickable": + return ASSERT_NOT_CLICKABLE; + case "assert visible": + return ASSERT_VISIBLE; + case "assert not visible": + return ASSERT_NOT_VISIBLE; + case "assert element content is": + return ASSERT_ELEM_CONTENT_IS; + case "assert element content has": + return ASSERT_ELEM_CONTENT_HAS; + case "assert element class is": + return ASSERT_ELEM_CLASS_IS; + case "assert element class has": + return ASSERT_ELEM_CLASS_HAS; + case "assert element has attribute": + return ASSERT_ELEM_HAS_ATTRIBUTE; + case "assert element not has attribute": + return ASSERT_ELEM_NOT_HAS_ATTRIBUTE; + case "alert": + return ALERT; + default: + throw new ParsingException("Invalid session action \"" + s + "\""); + } + } + } + + /** + * Defines the action of a session operation + */ + public enum SessOperationAction { + SAVE, + INSERT, + MARKER, + REMOVE + } + + /** + * Defines the target of a session operation. + * Is it better to use js or just build a form? if a form is used, body has to be interpreted + */ + public enum SessOperationTarget { + LAST_ACTION, + LAST_ACTION_ELEM, + LAST_ACTION_ELEM_PARENT, + LAST_CLICK, + LAST_CLICK_ELEM, + LAST_CLICK_ELEM_PARENT, + LAST_OPEN, + LAST_OPEN_ELEM, + LAST_URL, + ALL_ASSERT, + TRACK; + + /** + * Parse a string containing a session operation target + * + * @param s the string to parse + * @throws ParsingException if the string is malformed, or no session operation target is found + */ + public static SessOperationTarget getFromString(String s) throws ParsingException { + + if (s.contains(".")) { + String[] splitted; + splitted = s.split("\\."); + String left = splitted[0]; + boolean parent = false; + if (splitted.length == 3) { + if (splitted[2].equals("parent")) { + parent = true; + } + } + + switch (s) { + case "last_action.elem": + case "last_action.elem.parent": + return parent ? LAST_ACTION_ELEM_PARENT : LAST_ACTION_ELEM; + case "last_click.elem": + case "last_click.elem.parent": + return parent ? LAST_CLICK_ELEM_PARENT : LAST_CLICK_ELEM; + case "last_open.elem": + return LAST_OPEN_ELEM; + case "last_url": + return LAST_URL; + case "all_assert": + return ALL_ASSERT; + default: + throw new ParsingException("invalid target in session operation"); + } + } else { + switch (s) { + case "track": + return TRACK; + case "last_action": + return LAST_ACTION; + case "last_click": + return LAST_CLICK; + case "last_open": + return LAST_OPEN; + case "last_url": + return LAST_URL; + case "all_assert": + return ALL_ASSERT; + default: + throw new ParsingException("invalid target in session operation"); + } + } + } + } } diff --git a/tool/src/main/java/migt/SessionTrackAction.java b/tool/src/main/java/migt/SessionTrackAction.java index 8f334f2..92b6a09 100644 --- a/tool/src/main/java/migt/SessionTrackAction.java +++ b/tool/src/main/java/migt/SessionTrackAction.java @@ -10,7 +10,7 @@ * @author Matteo Bitussi */ public class SessionTrackAction { - public Utils.SessAction action; + public SessionOperation.SessAction action; public String elem_type; public String elem_source; public String elem; @@ -56,18 +56,18 @@ public void parse_raw_action(String raw_action) throws ParsingException { throw new ParsingException("invalid session action \"" + raw_action + "\""); } - action = Utils.SessAction.getFromString(splitted[0].trim()); + action = SessionOperation.SessAction.getFromString(splitted[0].trim()); if (splitted[0].trim().contains("assert")) { isAssert = true; } - if (action == Utils.SessAction.CLEAR_COOKIES) return; + if (action == SessionOperation.SessAction.CLEAR_COOKIES) return; elem = splitted[1].trim(); - if (!(action == Utils.SessAction.OPEN) && - action != Utils.SessAction.WAIT && - action != Utils.SessAction.ALERT && - action != Utils.SessAction.SET_VAR) { + if (!(action == SessionOperation.SessAction.OPEN) && + action != SessionOperation.SessAction.WAIT && + action != SessionOperation.SessAction.ALERT && + action != SessionOperation.SessAction.SET_VAR) { String[] tmp = elem.split("="); elem_type = tmp[0].trim(); elem_source = tmp[1].trim(); @@ -155,7 +155,7 @@ public String toString() { case CLEAR_COOKIES: break; } - if (action == Utils.SessAction.TYPE) { + if (action == SessionOperation.SessAction.TYPE) { res += " " + content; } diff --git a/tool/src/main/java/migt/Test.java b/tool/src/main/java/migt/Test.java index 72f0754..125c030 100644 --- a/tool/src/main/java/migt/Test.java +++ b/tool/src/main/java/migt/Test.java @@ -21,7 +21,7 @@ * @author Matteo Bitussi */ public class Test { - public Utils.ResultType result; + public ResultType result; public String resultSession; public List sessions; public String references; @@ -115,7 +115,7 @@ public Test(JSONObject test_json, if (test_json.has("result")) { String tmp = test_json.getString("result"); if (tmp.contains("assert_only")) { - result = Utils.ResultType.fromString(tmp); + result = ResultType.fromString(tmp); } else { tmp = tmp.trim(); String[] splitted = tmp.split("flow"); @@ -123,7 +123,7 @@ public Test(JSONObject test_json, if (splitted.length > 1) { resultSession = splitted[1].trim(); } - result = Utils.ResultType.fromString(splitted[0].trim()); + result = ResultType.fromString(splitted[0].trim()); } } } @@ -188,7 +188,7 @@ public List getRows() { String.valueOf(count), String.valueOf(op.getMessageType()), String.valueOf(op.getMessageSection()), - op.isRegex ? op.getRegex() : op.getChecks().toString(), + op.getChecks().toString(), msg.index.toString(), msg.isFail ? "failed" : "passed"}; res.add(tmp); @@ -380,4 +380,37 @@ public void logTest(String log_folder) { op_count++; } } + + /** + * The result type of (also the oracle) of an Active test + */ + public enum ResultType { + CORRECT_FLOW, + INCORRECT_FLOW, + ASSERT_ONLY; + + /** + * From a string get the corresponding enum value + * + * @param input the string + * @return the enum value + * @throws ParsingException if the input is malformed + */ + public static ResultType fromString(String input) throws ParsingException { + if (input != null) { + switch (input) { + case "correct": + return CORRECT_FLOW; + case "incorrect": + return INCORRECT_FLOW; + case "assert_only": + return ASSERT_ONLY; + default: + throw new ParsingException("invalid result"); + } + } else { + throw new NullPointerException(); + } + } + } } diff --git a/tool/src/main/java/migt/Tools.java b/tool/src/main/java/migt/Tools.java index 6b0565d..ee594ed 100644 --- a/tool/src/main/java/migt/Tools.java +++ b/tool/src/main/java/migt/Tools.java @@ -1,9 +1,12 @@ package migt; import burp.IExtensionHelpers; -import burp.IParameter; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.PathNotFoundException; +import org.json.JSONArray; +import org.json.JSONObject; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.regex.Matcher; @@ -33,8 +36,6 @@ public static boolean executePassiveTest(Test test, boolean actisreq = false; boolean actisresp = false; - int first_message_index = getInitMessageIndex(messageList, helpers); - for (i = 0; i < messageList.size(); i++) { j = 0; while (j < test.operations.size() && res) { @@ -221,41 +222,6 @@ public static boolean processOperation(Operation currentOP, null ); - if (currentOP.isRegex) { - try { - res = !isRequest || Tools.findInMessage( - currentOP.getMessageSection(), currentOP.getRegex(), message, helpers, true); - if (!res) { - if (isRequest) - currentOP.matchedMessages.add( - new Operation.MatchedMessage( - message, message_index, true, false, true)); - return false; - } - res = isRequest || Tools.findInMessage( - currentOP.getMessageSection(), currentOP.getRegex(), message, helpers, false); - if (!res) { - if (!isRequest) - currentOP.matchedMessages.add( - new Operation.MatchedMessage( - message, message_index, false, true, true)); - return false; - } - - if (isRequest) - currentOP.matchedMessages.add( - new Operation.MatchedMessage( - message, message_index, true, false, false)); - if (!isRequest) - currentOP.matchedMessages.add( - new Operation.MatchedMessage( - message, message_index, false, true, false)); - } catch (ParsingException e) { - currentOP.applicable = false; - System.err.println(e); - } - - } if (currentOP.hasChecks()) { try { res = !isRequest || Tools.executeChecks( @@ -300,10 +266,10 @@ public static boolean processOperation(Operation currentOP, * @param section the section of the message to be checked with the regex * @param regex the regex * @param message the message to be checked - * @param helpers an istance of the helpers + * @param helpers an instance of the helpers * @return the result of the check, if the regex matches 1 or more time it returns true */ - public static boolean findInMessage(Utils.MessageSection section, + public static boolean findInMessage(HTTPReqRes.MessageSection section, String regex, HTTPReqRes message, IExtensionHelpers helpers, @@ -380,7 +346,7 @@ public static boolean findInMessage(Utils.MessageSection section, } /** - * Function that given a list of headers, concatenate them in a single string + * Function that given a list of headers, concatenates them in a single string * * @param headers the list of headers * @return the string @@ -394,54 +360,6 @@ public static String getAllHeaders(List headers) { return out.toString(); } - /** - * This method retrieves Authorization Grant (Response) - Start of OAuth flow - * - * @param messageList the list of HTTPReqRes messages over search to - * @param helpers an instance of the helpers - * @return the index of the Authorization GRant message in the list of messages - */ - public static int getInitMessageIndex(List messageList, IExtensionHelpers helpers) { - int result = -1; - for (int i = 0; i < messageList.size() && result < 0; i++) - if (helpers.bytesToString(messageList.get(i).getResponse()).contains("response_type")) - result = i; - - return result; - } - - /** - * This method checks if the give message is an Authorization Grant Response - * - * @param messageInfo the message to check - * @param helpers an istance of the helpers - * @return a boolean true or false - */ - public static boolean isFirstMessage(HTTPReqRes messageInfo, IExtensionHelpers helpers) { - return helpers.bytesToString(messageInfo.getResponse()).contains("response_type=code"); - } - - /** - * This method checks if the messageInfo is the last message of the OAuth flow - * - * @param messageInfo the message - * @param helpers the helpers - * @return a boolean true or false - */ - public static boolean isLastMessage(HTTPReqRes messageInfo, IExtensionHelpers helpers) { - String rawBody = helpers.bytesToString(messageInfo.getResponse()); - boolean result = false; - List requestParams = helpers.analyzeRequest(messageInfo.getRequest()).getParameters(); - for (int i = 0; i < requestParams.size(); i++) { - - if (requestParams.get(i).getName().equals("code")) { - result = true; - } - } - //return result && rawBody.contains("access_token"); - return result; - } - /** * This function execute a list of checks over a message, returning true if all the checks are successful * @@ -472,6 +390,7 @@ public static boolean executeChecks(List checks, * @throws ParsingException */ public static boolean executeChecks(Operation op) throws ParsingException { + // TODO for (Check c : op.getChecks()) { c.loader(op.api); //TODO: change loader to an Operation api c.execute(); @@ -482,34 +401,14 @@ public static boolean executeChecks(Operation op) throws ParsingException { return true; } - /** - * Function that gets all the parameters of an url - * (stackoverflow) - * - * @param url the url from which extract the parameters - * @return all the parameters - */ - public static Map getUrlParams(URL url) { - String query = url.getQuery(); - String[] params = query.split("&"); - Map map = new HashMap(); - - for (String param : params) { - String name = param.split("=")[0]; - String value = param.split("=")[1]; - map.put(name, value); - } - return map; - } - /** * Executes the decode operations in an operation. Uses APIs. Sets the result to the operation * - * @param op - * @param helpers - * @param mainPane - * @return - * @throws ParsingException + * @param op the operation to execute the decode operations from + * @param helpers the Burp helpers + * @param mainPane reference to the mainPane object (contains the variables) + * @return The operation (edited) + * @throws ParsingException if something goes wrong */ public static Operation executeDecodeOps(Operation op, IExtensionHelpers helpers, @@ -531,9 +430,9 @@ public static Operation executeDecodeOps(Operation op, * * @param op the decode operation executing its child decode operations * @param helpers the burp helpers - * @param mainPane - * @return - * @throws ParsingException + * @param mainPane reference to the mainPane object (contains the variables) + * @return The operation (edited) + * @throws ParsingException if something goes wrong */ public static DecodeOperation executeDecodeOps(DecodeOperation op, IExtensionHelpers helpers, @@ -550,8 +449,15 @@ public static DecodeOperation executeDecodeOps(DecodeOperation op, return op; } + /** + * Executes the edit operations inside of a decode operation + * + * @param op the decode operation to run the edit operations from + * @param mainPane reference to the mainPane object (contains the variables) + * @return the Decode operation (edited) + * @throws ParsingException if something goes wrong + */ public static DecodeOperation executeEditOps(DecodeOperation op, - IExtensionHelpers helpers, GUI mainPane) throws ParsingException { DecodeOperation_API api = op.getAPI(); for (EditOperation eop : op.editOperations) { @@ -564,4 +470,680 @@ public static DecodeOperation executeEditOps(DecodeOperation op, return op; } + + /** + * Function that parses checks from a JSON array + * + * @param checks_array the JSONarray that should contain checks + * @return a List of Check elements + * @throws ParsingException if the input is malformed + */ + public static List parseChecksFromJSON(JSONArray checks_array) throws ParsingException { + List res = new ArrayList<>(); + for (int k = 0; k < checks_array.length(); k++) { + JSONObject act_check = checks_array.getJSONObject(k); + Check check = new Check(act_check); + + if (check.in == null) { + throw new ParsingException("In tag cannot be empty"); + } + res.add(check); + } + return res; + } + + /** + * Parses a list of Edit operations from a JSON array + * + * @param edits_array the input JSON array containing the edit operations + * @return the parsed list of Edit operations + * @throws ParsingException if there are problems parsing the JSON array + */ + public static List parseEditsFromJSON(JSONArray edits_array) throws ParsingException { + List res = new ArrayList<>(); + for (int i = 0; i < edits_array.length(); i++) { + JSONObject act_edit = edits_array.getJSONObject(i); + EditOperation edit = new EditOperation(act_edit); + res.add(edit); + } + return res; + } + + /** + * Function used to parse the message types from a string + * + * @param input a string containing the msg types in JSON + * @return a List of messagetype objects + * @throws ParsingException if the input is malformed + */ + public static List readMsgTypeFromJson(String input) throws ParsingException { + List msg_types = new ArrayList<>(); + + JSONObject obj = new JSONObject(input); + JSONArray message_types = obj.getJSONArray("message_types"); + + for (int i = 0; i < message_types.length(); i++) { + JSONObject act_msg_type = message_types.getJSONObject(i); + + String name = act_msg_type.getString("name"); + Boolean isRequest = act_msg_type.getBoolean("is request"); + + MessageType msg_obj = new MessageType(name, isRequest); + + if (act_msg_type.has("response name")) { + msg_obj.responseName = act_msg_type.getString("response name"); + } + if (act_msg_type.has("request name")) { + msg_obj.requestName = act_msg_type.getString("request name"); + } + + if (act_msg_type.has("checks")) { + msg_obj.isRegex = false; + msg_obj.checks = parseChecksFromJSON(act_msg_type.getJSONArray("checks")); + } else if (act_msg_type.has("regex")) { + msg_obj.isRegex = true; + msg_obj.regex = act_msg_type.getString("regex"); + msg_obj.messageSection = HTTPReqRes.MessageSection.fromString(act_msg_type.getString("message section")); + } else { + throw new ParsingException("message type definition is invalid, no checks or regex found"); + } + msg_types.add(msg_obj); + } + + return msg_types; + } + + /** + * Returns the default string that contains the default message types that fill a msg_def.json file + * + * @return the string + */ + public static String getDefaultJSONMsgType() { + return "{\n" + + " \"message_types\": [\n" + + " {\n" + + " \"name\": \"authorization request\",\n" + + " \"is request\": true,\n" + + " \"response name\": \"authorization response\",\n" + + " \"checks\": [\n" + + " {\n" + + " \"in\": \"url\",\n" + + " \"check param\": \"response_type\",\n" + + " \"is present\": \"true\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"token request\",\n" + + " \"is request\": true,\n" + + " \"response name\": \"token response\",\n" + + " \"checks\": [\n" + + " {\n" + + " \"in\": \"url\",\n" + + " \"check param\": \"code\",\n" + + " \"is present\": \"true\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"coda landing request\",\n" + + " \"is request\": true,\n" + + " \"response name\": \"coda landing response\",\n" + + " \"checks\": [\n" + + " {\n" + + " \"in\": \"url\",\n" + + " \"check\": \"/welcome\",\n" + + " \"is present\": \"true\"\n" + + " },\n" + + " {\n" + + " \"in\": \"head\",\n" + + " \"check\": \"Host\",\n" + + " \"is\": \"coda.io\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"saml request\",\n" + + " \"is request\": true,\n" + + " \"checks\": [\n" + + " {\n" + + " \"in\": \"url\",\n" + + " \"check param\": \"SAMLRequest\",\n" + + " \"is present\": true\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"saml response\",\n" + + " \"is request\": true,\n" + + " \"checks\": [\n" + + " {\n" + + " \"in\": \"body\",\n" + + " \"check param\": \"SAMLResponse\",\n" + + " \"is present\": true\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}"; + } + + /** + * Returns the default string that contains the default config for the config.json file + * + * @return the string + */ + public static String getDefaultJSONConfig() { + return "{\n" + + " \"last_driver_path\":\"\",\n" + + " \"last_browser_used\": \"\"\n" + + "}"; + } + + /** + * Removes all the newlines from a string + * + * @return the edited message + */ + public static String removeNewline(String input) { + Pattern p = Pattern.compile("\n"); + Matcher m = p.matcher(input); + + String out = m.replaceAll(""); + return out; + } + + /** + * Builds a string, substituting variables names with values + * + * @param vars the list of variables to use + * @param s the string + * @return the builded string + * @throws ParsingException if a variable is not found + */ + public static String buildStringWithVars(List vars, String s) throws ParsingException { + Pattern p = Pattern.compile("\\$[^\\$]*\\$"); + Matcher m = p.matcher(s); + + String res = s; + + HashMap req_var = new HashMap<>(); + + while (m.find()) { + String act_match = m.group(); + act_match = act_match.replaceAll("\\$", ""); + req_var.put(act_match, getVariableByName(act_match, vars).value); + } + + if (req_var.size() == 0) { + return s; + } + + for (String key : req_var.keySet()) { + res = res.replaceAll("\\$" + key + "\\$", Matcher.quoteReplacement(req_var.get(key))); + } + return res; + } + + /** + * Given a name, returns the corresponding variable + * + * @param name the name of the variable + * @return the Var object + * @throws ParsingException if the variable cannot be found + */ + public static Var getVariableByName(String name, List vars) throws ParsingException { + for (Var act : vars) { + if (act.name.equals(name)) { + return act; + } + } + throw new ParsingException("variable \"" + name + "\" not defined"); + } + + /** + * Generates a CSRF POC from an HTTP request message + * + * @param message the message to generate the POC from + * @param helpers Burp's IExtensionHelper instance + * @return the html poc as a string + */ + public static String generate_CSRF_POC(HTTPReqRes message, + IExtensionHelpers helpers) { + + String CSFR_TEMPLATE = "\n" + + "\n" + + " \n" + + "

Attack Page

\n" + + "

Service Provider (SP) is your service.

\n" + + "

Identity Provider (IdP) is the provider with which the SP allows to associate the account.

\n" + + "

These are the steps to reproduce the attack:

\n" + + "

1. The victim clicks on button to initiate force-login to IdP and victim logs in as the attacker because IdP suffering of Pre-Authentication Login CSRF. To simulate this step, the victim logs in with the attacker's IdP credentials.

\n" + + "

2. The victim logins at SP with victim credentials.

\n" + + "

3. The victim clicks on following link which suffers of CSRF, to associate attacker IdP account with the Victim SP account.

\n" + + " $INSERT_HERE$\n" + + "
\n" + + "

4. If the IdP attacker account has been associated with the victim SP account then the vulnerability has been properly exploited.

\n" + + " \n" + + ""; + + String POST_TEMPLATE = + "
\n" + + " \n" + + " $BODY_PARAMETERS$\n" + + "
\n" + + " \n" + + "
\n"; + + String TEMPLATE_BODY_PARAMS = " \n" + + " $PARAM_NAME$\n" + + " \n" + + " \n" + + " \n" + + " "; + + List headers = message.getHeaders(true); + String encoding = message.getHeadParam(true, "Content-Type").strip(); + String body = new String(message.getBody(true), StandardCharsets.UTF_8); // splitMessage(message, helpers, true).get(2); + String url = message.getUrl(); + String method = message.getUrlHeader().split(" ")[0]; + + Pattern p = Pattern.compile(""); + Matcher m = p.matcher(body); + + String res = ""; + + res = POST_TEMPLATE; + p = Pattern.compile("\\$ENCODING_TYPE\\$"); + m = p.matcher(res); + res = m.replaceAll(encoding); + + p = Pattern.compile("\\$METHOD\\$"); + m = p.matcher(res); + res = m.replaceAll(method); + + if (method.equals("POST")) { + p = Pattern.compile("([^=]*)=([^&\\n$]*)(&|\\n|$)"); + m = p.matcher(body); + String out_body_params = ""; + + if (body.length() != 0) { + Map body_params = new HashMap<>(); + while (m.find()) { + String name = m.group(1); + String value = m.group(2); + if (name.length() != 0) { + body_params.put(name, + value.length() != 0 ? value : ""); + } + } + for (String key : body_params.keySet()) { + String tmp = TEMPLATE_BODY_PARAMS; + p = Pattern.compile("\\$PARAM_NAME\\$"); + m = p.matcher(tmp); + + tmp = m.replaceAll(key); + + p = Pattern.compile("\\$PARAM_VALUE\\$"); + m = p.matcher(tmp); + + tmp = m.replaceAll(body_params.get(key)); + + out_body_params += tmp; + } + } + + p = Pattern.compile("\\$URL\\$"); + m = p.matcher(res); + res = m.replaceAll(url); + + p = Pattern.compile("\\$BODY_PARAMETERS\\$"); + m = p.matcher(res); + res = m.replaceAll(out_body_params); + } else { + boolean has_query_params = url.split("\\?").length > 1; + String out_query_params = ""; + + if (has_query_params) { + String raw_query_params = url.split("\\?")[1]; + + p = Pattern.compile("([^=\\n&]*)=([^=\\n&]*)"); + m = p.matcher(raw_query_params); + + Map query_params = new HashMap<>(); + while (m.find()) { + String name = m.group(1); + String value = m.group(2); + if (name.length() != 0) { + query_params.put(name, value.length() != 0 ? value : ""); + } + } + for (String key : query_params.keySet()) { + String tmp = TEMPLATE_BODY_PARAMS; + p = Pattern.compile("\\$PARAM_NAME\\$"); + m = p.matcher(tmp); + + tmp = m.replaceAll(key); + + p = Pattern.compile("\\$PARAM_VALUE\\$"); + m = p.matcher(tmp); + + tmp = m.replaceAll(query_params.get(key)); + + out_query_params += tmp; + } + } + + p = Pattern.compile("\\$URL\\$"); + m = p.matcher(res); + res = m.replaceAll(has_query_params ? url.split("\\?")[0] : url); + + p = Pattern.compile("\\$BODY_PARAMETERS\\$"); + m = p.matcher(res); + res = m.replaceAll(out_query_params); + } + + String tmp = CSFR_TEMPLATE; + p = Pattern.compile("\\$INSERT_HERE\\$"); + m = p.matcher(tmp); + tmp = m.replaceAll(res); + + return tmp; + } + + /** + * Create batches of passive tests, grouping them by the session they need to execute. + * + * @return An HashMap object having as keys, Strings representing the sessions names, and as value a list of tests + * that need to execute that session + */ + public static HashMap> batchPassivesFromSession(List testList) throws ParsingException { + HashMap> batch = new HashMap<>(); + for (Test t : testList) { + if (t.sessions.size() == 0) { + throw new ParsingException("Undefined session in test " + t.name); + } + + if (!batch.containsKey(t.sessions.get(0).name)) { + List n = new ArrayList<>(); + n.add(t); + batch.put(t.sessions.get(0).name, n); + } else { + List tmp = batch.get(t.sessions.get(0).name); + tmp.add(t); + batch.put(t.sessions.get(0).name, tmp); + } + } + return batch; + } + + /** + * From a batch of tests grouped by sessions, return a list containing all the tests + * + * @param batch the batch of tests in the form of a MAP> + * @return a list containing all the tests + */ + public static List debatchPassive(HashMap> batch) { + List res = new ArrayList<>(); + for (String sessionName : batch.keySet()) { + for (Test t : batch.get(sessionName)) { + res.add(t); + } + } + return res; + } + + /** + * Edit a message treating it as a string using a regex + * + * @param helpers an instance of Burp's IExtensionHelper + * @param regex the regex used to match the things to change + * @param mop the message operation containing information about the section to match the regex + * @param messageInfo the message as IHttpRequestResponse object + * @param isRequest specify if the message to consider is the request or response + * @param new_value the new value to substitute to the message section + * @return the edited message as byte array + * @throws ParsingException if problems are encountered in editing the message + */ + public static byte[] editMessage(IExtensionHelpers helpers, + String regex, + MessageOperation mop, + HTTPReqRes messageInfo, + boolean isRequest, + String new_value) throws ParsingException { + // TODO: remove dependency from Helpers + Pattern pattern = null; + Matcher matcher = null; + switch (mop.from) { + case HEAD: + List head = messageInfo.getHeaders(isRequest); + pattern = Pattern.compile(regex); + List new_head = new ArrayList<>(); + + for (String act_header : head) { + matcher = pattern.matcher(act_header); + new_head.add(matcher.replaceAll(new_value)); + } + messageInfo.setHeaders(isRequest, new_head); + return messageInfo.getMessage(isRequest, helpers); + + case BODY: + pattern = Pattern.compile(regex); + + matcher = pattern.matcher(new String(messageInfo.getBody(isRequest))); + messageInfo.setBody(isRequest, matcher.replaceAll(new_value)); + //Automatically update content-lenght + return messageInfo.getMessage(isRequest, helpers); + + case URL: + if (!isRequest) { + throw new ParsingException("Encoding URL in response"); + } + + pattern = Pattern.compile(regex); + matcher = pattern.matcher(messageInfo.getUrlHeader()); + String replaced = matcher.replaceAll(new_value); + messageInfo.setUrlHeader(replaced); + + return messageInfo.getMessage(isRequest, helpers); + } + return null; + } + + /** + * Edit a message parameter + * + * @param helpers an instance of Burp's IExtensionHelper + * @param param_name the name of the parameter to edit + * @param message_section the message section to edit + * @param messageInfo the message as IHttpRequestResponse object + * @param isRequest specify if the message to consider is the request or response + * @param new_value the new value of the parameter + * @param isBodyRegex when the section is body, set it to true if you want to use a regex to substitute the value, + * otherwise a parameter param=... is searched + * @return the edited message as byte array + * @throws ParsingException if problems are encountered in editing the message + */ + public static byte[] editMessageParam(IExtensionHelpers helpers, + String param_name, + HTTPReqRes.MessageSection message_section, + HTTPReqRes messageInfo, + boolean isRequest, + String new_value, + boolean isBodyRegex) throws ParsingException { + List splitted = null; + Pattern pattern = null; + Matcher matcher = null; + switch (message_section) { + case HEAD: + messageInfo.editHeadParam(isRequest, param_name, new_value); + byte[] message = messageInfo.getMessage(isRequest, helpers); + messageInfo.setHost(new_value); // this should be set when the message is converted to the burp class + return message; + + case BODY: + if (!isBodyRegex) { + pattern = Pattern.compile("(?<=" + param_name + "=)[^$\\n& ]*"); + } else { + pattern = Pattern.compile(param_name); + } + + matcher = pattern.matcher(new String(messageInfo.getBody(isRequest))); + messageInfo.setBody(isRequest, matcher.replaceAll(new_value)); + //Automatically update content-lenght + return messageInfo.getMessage(isRequest, helpers); + + case URL: + if (!isRequest) { + throw new ParsingException("Encoding URL in response"); + } + String url_header = messageInfo.getUrlHeader(); + + pattern = Pattern.compile(param_name + "=[^& ]*((?=&)|(?= ))"); + matcher = pattern.matcher(url_header); + + messageInfo.setUrlHeader(matcher.replaceAll(param_name + "=" + new_value)); // problema + + return messageInfo.getMessage(isRequest, helpers); + } + return null; + } + + public static byte[] editMessageParam(IExtensionHelpers helpers, + String param_name, + DecodeOperation.DecodeOperationFrom decodeOperationFrom, + HTTPReqRes messageInfo, + boolean isRequest, + String new_value, + boolean isBodyRegex) throws ParsingException { + + HTTPReqRes.MessageSection ms = null; + + switch (decodeOperationFrom) { + case HEAD: + ms = HTTPReqRes.MessageSection.HEAD; + break; + case BODY: + ms = HTTPReqRes.MessageSection.BODY; + break; + case URL: + ms = HTTPReqRes.MessageSection.URL; + break; + case JWT_HEADER: + case JWT_PAYLOAD: + case JWT_SIGNATURE: + throw new ParsingException("invalid from section in decode operation should be a message section"); + } + + return editMessageParam( + helpers, + param_name, + ms, + messageInfo, + isRequest, + new_value, + isBodyRegex + ); + } + + /** + * Given a name, returns the corresponding variable + * + * @param name the name of the variable + * @return the Var object + * @throws ParsingException if the variable cannot be found + */ + public static Var getVariableByName(String name, GUI mainPane) throws ParsingException { + synchronized (mainPane.lock) { + for (Var act : mainPane.act_test_vars) { + if (act.name.equals(name)) { + return act; + } + } + } + throw new ParsingException("variable not defined"); + } + + /** + * Finds the parent div of an http element + * + * @param in the http element in xpath format + * @return the xpath of the parent div + * @throws ParsingException if no parent div present or input is malformed + */ + public static String findParentDiv(String in) throws ParsingException { + String[] split1 = in.split("="); + if (split1.length != 2) { + throw new ParsingException("invalid input \"" + in + "\" for finding parent div"); + } + String[] split = split1[1].split("/"); + if (split.length == 0) { + return in; + } + + int cut_indx = -1; + + //-2 because if the last element is a div i don't take it, otherwise is not a div, so i don't take it + for (int i = split.length - 2; i > 0; i--) { + if (split[i].contains("div")) { + cut_indx = i; + break; + } + } + if (cut_indx == -1) return in; + + String res = split1[0] + "="; + + for (int i = 1; i <= cut_indx; i++) { + if (i == cut_indx) { + // removes the index of the div element + res += "/" + split[i].replaceAll("\\[.*\\]", ""); + } else { + res += "/" + split[i]; + } + } + return res; + } + + /** + * Given a json string and a json path, edit the json. + * + * @param action the action to do, (edit, remove, add, or save) + * @param content the json content as string + * @param j_path the json path as string + * @param mainPane the mainPane reference, to access the variables + * @param save_as the name of the variable if the action is save + * @return the edited json + * @throws PathNotFoundException if the path in the json is not found + */ + public static String editJson(EditOperation.Jwt_action action, + String content, + String j_path, + GUI mainPane, + String save_as, + String newValue) throws PathNotFoundException { + Object document = Configuration.defaultConfiguration().jsonProvider().parse(content); + JsonPath jsonPath = JsonPath.compile(j_path); + + switch (action) { + case REMOVE: + document = jsonPath.delete(document, Configuration.defaultConfiguration()); + break; + case EDIT: + case ADD: + document = jsonPath.set(document, newValue, Configuration.defaultConfiguration()); + //TODO: check if set also adds in case it is not found + break; + case SAVE: + Var v = new Var(); + v.name = save_as; + v.isMessage = false; + v.value = JsonPath.read(content, j_path); //TODO could rise errors + synchronized (mainPane.lock) { + mainPane.act_test_vars.add(v); + } + break; + } + return Configuration.defaultConfiguration().jsonProvider().toJson(document); //basically converts to string + } } diff --git a/tool/src/main/java/migt/Utils.java b/tool/src/main/java/migt/Utils.java deleted file mode 100644 index a1ecebc..0000000 --- a/tool/src/main/java/migt/Utils.java +++ /dev/null @@ -1,1404 +0,0 @@ -package migt; - -import burp.IExtensionHelpers; -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.PathNotFoundException; -import org.json.JSONArray; -import org.json.JSONObject; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * class containing useful methods and enums to be used in other classes - * - * @author Matteo Bitussi - */ -public class Utils { - /** - * Function that parses checks from a JSON array - * - * @param checks_array the JSONarray that should contain checks - * @return a List of Check elements - * @throws ParsingException if the input is malformed - */ - public static List parseChecksFromJSON(JSONArray checks_array) throws ParsingException { - List res = new ArrayList<>(); - for (int k = 0; k < checks_array.length(); k++) { - JSONObject act_check = checks_array.getJSONObject(k); - Check check = new Check(act_check); - - if (check.in == null) { - throw new ParsingException("In tag cannot be empty"); - } - res.add(check); - } - return res; - } - - public static List parseEditsFromJSON(JSONArray edits_array) throws ParsingException { - List res = new ArrayList<>(); - for (int i = 0; i < edits_array.length(); i++) { - JSONObject act_edit = edits_array.getJSONObject(i); - EditOperation edit = new EditOperation(act_edit); - res.add(edit); - } - return res; - } - - /** - * Function used to parse the message types from a string - * - * @param input a string containing the msg types in JSON - * @return a List of messagetype objects - * @throws ParsingException if the input is malformed - */ - public static List readMsgTypeFromJson(String input) throws ParsingException { - List msg_types = new ArrayList<>(); - - JSONObject obj = new JSONObject(input); - JSONArray message_types = obj.getJSONArray("message_types"); - - for (int i = 0; i < message_types.length(); i++) { - JSONObject act_msg_type = message_types.getJSONObject(i); - - String name = act_msg_type.getString("name"); - Boolean isRequest = act_msg_type.getBoolean("is request"); - - MessageType msg_obj = new MessageType(name, isRequest); - - if (act_msg_type.has("response name")) { - msg_obj.responseName = act_msg_type.getString("response name"); - } - if (act_msg_type.has("request name")) { - msg_obj.requestName = act_msg_type.getString("request name"); - } - - if (act_msg_type.has("checks")) { - msg_obj.isRegex = false; - msg_obj.checks = parseChecksFromJSON(act_msg_type.getJSONArray("checks")); - } else if (act_msg_type.has("regex")) { - msg_obj.isRegex = true; - msg_obj.regex = act_msg_type.getString("regex"); - msg_obj.messageSection = Utils.MessageSection.fromString(act_msg_type.getString("message section")); - } else { - throw new ParsingException("message type definition is invalid, no checks or regex found"); - } - msg_types.add(msg_obj); - } - - return msg_types; - } - - /** - * Returns the default string that contains the default message types that fill a msg_def.json file - * - * @return the string - */ - public static String getDefaultJSONMsgType() { - return "{\n" + - " \"message_types\": [\n" + - " {\n" + - " \"name\": \"authorization request\",\n" + - " \"is request\": true,\n" + - " \"response name\": \"authorization response\",\n" + - " \"checks\": [\n" + - " {\n" + - " \"in\": \"url\",\n" + - " \"check param\": \"response_type\",\n" + - " \"is present\": \"true\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " {\n" + - " \"name\": \"token request\",\n" + - " \"is request\": true,\n" + - " \"response name\": \"token response\",\n" + - " \"checks\": [\n" + - " {\n" + - " \"in\": \"url\",\n" + - " \"check param\": \"code\",\n" + - " \"is present\": \"true\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " {\n" + - " \"name\": \"coda landing request\",\n" + - " \"is request\": true,\n" + - " \"response name\": \"coda landing response\",\n" + - " \"checks\": [\n" + - " {\n" + - " \"in\": \"url\",\n" + - " \"check\": \"/welcome\",\n" + - " \"is present\": \"true\"\n" + - " },\n" + - " {\n" + - " \"in\": \"head\",\n" + - " \"check\": \"Host\",\n" + - " \"is\": \"coda.io\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " {\n" + - " \"name\": \"saml request\",\n" + - " \"is request\": true,\n" + - " \"checks\": [\n" + - " {\n" + - " \"in\": \"url\",\n" + - " \"check param\": \"SAMLRequest\",\n" + - " \"is present\": true\n" + - " }\n" + - " ]\n" + - " },\n" + - " {\n" + - " \"name\": \"saml response\",\n" + - " \"is request\": true,\n" + - " \"checks\": [\n" + - " {\n" + - " \"in\": \"body\",\n" + - " \"check param\": \"SAMLResponse\",\n" + - " \"is present\": true\n" + - " }\n" + - " ]\n" + - " }\n" + - " ]\n" + - "}"; - } - - /** - * Returns the default string that contains the default config for the config.json file - * - * @return the string - */ - public static String getDefaultJSONConfig() { - return "{\n" + - " \"last_driver_path\":\"\",\n" + - " \"last_browser_used\": \"\"\n" + - "}"; - } - - /** - * Removes all the newlines from a string - * - * @return the edited message - */ - public static String removeNewline(String input) { - Pattern p = Pattern.compile("\n"); - Matcher m = p.matcher(input); - - String out = m.replaceAll(""); - return out; - } - - /** - * Builds a string, substituting variables names with values - * - * @param vars the list of variables to use - * @param s the string - * @return the builded string - * @throws ParsingException if a variable is not found - */ - public static String buildStringWithVars(List vars, String s) throws ParsingException { - Pattern p = Pattern.compile("\\$[^\\$]*\\$"); - Matcher m = p.matcher(s); - - String res = s; - - HashMap req_var = new HashMap<>(); - - while (m.find()) { - String act_match = m.group(); - act_match = act_match.replaceAll("\\$", ""); - req_var.put(act_match, getVariableByName(act_match, vars).value); - } - - if (req_var.size() == 0) { - return s; - } - - for (String key : req_var.keySet()) { - res = res.replaceAll("\\$" + key + "\\$", Matcher.quoteReplacement(req_var.get(key))); - } - return res; - } - - /** - * Given a name, returns the corresponding variable - * - * @param name the name of the variable - * @return the Var object - * @throws ParsingException if the variable cannot be found - */ - public static Var getVariableByName(String name, List vars) throws ParsingException { - for (Var act : vars) { - if (act.name.equals(name)) { - return act; - } - } - throw new ParsingException("variable \"" + name + "\" not defined"); - } - - /** - * Generates a CSRF POC from an HTTP request message - * - * @param message the message to generate the POC from - * @param helpers Burp's IExtensionHelper instance - * @return the html poc as a string - */ - public static String generate_CSRF_POC(HTTPReqRes message, - IExtensionHelpers helpers) { - - String CSFR_TEMPLATE = "\n" + - "\n" + - " \n" + - "

Attack Page

\n" + - "

Service Provider (SP) is your service.

\n" + - "

Identity Provider (IdP) is the provider with which the SP allows to associate the account.

\n" + - "

These are the steps to reproduce the attack:

\n" + - "

1. The victim clicks on button to initiate force-login to IdP and victim logs in as the attacker because IdP suffering of Pre-Authentication Login CSRF. To simulate this step, the victim logs in with the attacker's IdP credentials.

\n" + - "

2. The victim logins at SP with victim credentials.

\n" + - "

3. The victim clicks on following link which suffers of CSRF, to associate attacker IdP account with the Victim SP account.

\n" + - " $INSERT_HERE$\n" + - "
\n" + - "

4. If the IdP attacker account has been associated with the victim SP account then the vulnerability has been properly exploited.

\n" + - " \n" + - ""; - - String POST_TEMPLATE = - "
\n" + - " \n" + - " $BODY_PARAMETERS$\n" + - "
\n" + - " \n" + - "
\n"; - - String TEMPLATE_BODY_PARAMS = " \n" + - " $PARAM_NAME$\n" + - " \n" + - " \n" + - " \n" + - " "; - - List headers = message.getHeaders(true); - String encoding = message.getHeadParam(true, "Content-Type").strip(); - String body = new String(message.getBody(true), StandardCharsets.UTF_8); // splitMessage(message, helpers, true).get(2); - String url = message.getUrl(); - String method = message.getUrlHeader().split(" ")[0]; - - Pattern p = Pattern.compile(""); - Matcher m = p.matcher(body); - - String res = ""; - - res = POST_TEMPLATE; - p = Pattern.compile("\\$ENCODING_TYPE\\$"); - m = p.matcher(res); - res = m.replaceAll(encoding); - - p = Pattern.compile("\\$METHOD\\$"); - m = p.matcher(res); - res = m.replaceAll(method); - - if (method.equals("POST")) { - p = Pattern.compile("([^=]*)=([^&\\n$]*)(&|\\n|$)"); - m = p.matcher(body); - String out_body_params = ""; - - if (body.length() != 0) { - Map body_params = new HashMap<>(); - while (m.find()) { - String name = m.group(1); - String value = m.group(2); - if (name.length() != 0) { - body_params.put(name, - value.length() != 0 ? value : ""); - } - } - for (String key : body_params.keySet()) { - String tmp = TEMPLATE_BODY_PARAMS; - p = Pattern.compile("\\$PARAM_NAME\\$"); - m = p.matcher(tmp); - - tmp = m.replaceAll(key); - - p = Pattern.compile("\\$PARAM_VALUE\\$"); - m = p.matcher(tmp); - - tmp = m.replaceAll(body_params.get(key)); - - out_body_params += tmp; - } - } - - p = Pattern.compile("\\$URL\\$"); - m = p.matcher(res); - res = m.replaceAll(url); - - p = Pattern.compile("\\$BODY_PARAMETERS\\$"); - m = p.matcher(res); - res = m.replaceAll(out_body_params); - } else { - boolean has_query_params = url.split("\\?").length > 1; - String out_query_params = ""; - - if (has_query_params) { - String raw_query_params = url.split("\\?")[1]; - - p = Pattern.compile("([^=\\n&]*)=([^=\\n&]*)"); - m = p.matcher(raw_query_params); - - Map query_params = new HashMap<>(); - while (m.find()) { - String name = m.group(1); - String value = m.group(2); - if (name.length() != 0) { - query_params.put(name, value.length() != 0 ? value : ""); - } - } - for (String key : query_params.keySet()) { - String tmp = TEMPLATE_BODY_PARAMS; - p = Pattern.compile("\\$PARAM_NAME\\$"); - m = p.matcher(tmp); - - tmp = m.replaceAll(key); - - p = Pattern.compile("\\$PARAM_VALUE\\$"); - m = p.matcher(tmp); - - tmp = m.replaceAll(query_params.get(key)); - - out_query_params += tmp; - } - } - - p = Pattern.compile("\\$URL\\$"); - m = p.matcher(res); - res = m.replaceAll(has_query_params ? url.split("\\?")[0] : url); - - p = Pattern.compile("\\$BODY_PARAMETERS\\$"); - m = p.matcher(res); - res = m.replaceAll(out_query_params); - } - - String tmp = CSFR_TEMPLATE; - p = Pattern.compile("\\$INSERT_HERE\\$"); - m = p.matcher(tmp); - tmp = m.replaceAll(res); - - return tmp; - } - - /** - * Create batches of passive tests, grouping them by the session they need to execute. - * - * @return An HashMap object having as keys, Strings representing the sessions names, and as value a list of tests - * that need to execute that session - */ - public static HashMap> batchPassivesFromSession(List testList) throws ParsingException { - HashMap> batch = new HashMap<>(); - for (Test t : testList) { - if (t.sessions.size() == 0) { - throw new ParsingException("Undefined session in test " + t.name); - } - - if (!batch.containsKey(t.sessions.get(0).name)) { - List n = new ArrayList<>(); - n.add(t); - batch.put(t.sessions.get(0).name, n); - } else { - List tmp = batch.get(t.sessions.get(0).name); - tmp.add(t); - batch.put(t.sessions.get(0).name, tmp); - } - } - return batch; - } - - /** - * From a batch of tests grouped by sessions, return a list containing all the tests - * - * @param batch the batch of tests in the form of a MAP> - * @return - * @throws ParsingException - */ - public static List debatchPassive(HashMap> batch) { - List res = new ArrayList<>(); - for (String sessionName : batch.keySet()) { - for (Test t : batch.get(sessionName)) { - res.add(t); - } - } - return res; - } - - /** - * Edit a message treating it as a string using a regex - * - * @param helpers an instance of Burp's IExtensionHelper - * @param regex the regex used to match the things to change - * @param mop the message operation containing information about the section to match the regex - * @param messageInfo the message as IHttpRequestResponse object - * @param isRequest specify if the message to consider is the request or response - * @param new_value the new value to substitute to the message section - * @return the edited message as byte array - * @throws ParsingException if problems are encountered in editing the message - */ - public static byte[] editMessage(IExtensionHelpers helpers, - String regex, - MessageOperation mop, - HTTPReqRes messageInfo, - boolean isRequest, - String new_value) throws ParsingException { - // TODO: remove dependency from Helpers - Pattern pattern = null; - Matcher matcher = null; - switch (mop.from) { - case HEAD: - List head = messageInfo.getHeaders(isRequest); - pattern = Pattern.compile(regex); - List new_head = new ArrayList<>(); - - for (String act_header : head) { - matcher = pattern.matcher(act_header); - new_head.add(matcher.replaceAll(new_value)); - } - messageInfo.setHeaders(isRequest, new_head); - return messageInfo.getMessage(isRequest, helpers); - - case BODY: - pattern = Pattern.compile(regex); - - matcher = pattern.matcher(new String(messageInfo.getBody(isRequest))); - messageInfo.setBody(isRequest, matcher.replaceAll(new_value)); - //Automatically update content-lenght - return messageInfo.getMessage(isRequest, helpers); - - case URL: - if (!isRequest) { - throw new ParsingException("Encoding URL in response"); - } - - pattern = Pattern.compile(regex); - matcher = pattern.matcher(messageInfo.getUrlHeader()); - String replaced = matcher.replaceAll(new_value); - messageInfo.setUrlHeader(replaced); - - return messageInfo.getMessage(isRequest, helpers); - } - - return null; - } - - /** - * Edit a message parameter - * - * @param helpers an instance of Burp's IExtensionHelper - * @param param_name the name of the parameter to edit - * @param message_section the message section to edit - * @param messageInfo the message as IHttpRequestResponse object - * @param isRequest specify if the message to consider is the request or response - * @param new_value the new value of the parameter - * @param isBodyRegex when the section is body, set it to true if you want to use a regex to substitute the value, - * otherwise a parameter param=... is searched - * @return the edited message as byte array - * @throws ParsingException if problems are encountered in editing the message - */ - public static byte[] editMessageParam(IExtensionHelpers helpers, - String param_name, - Utils.MessageSection message_section, - HTTPReqRes messageInfo, - boolean isRequest, - String new_value, - boolean isBodyRegex) throws ParsingException { - List splitted = null; - Pattern pattern = null; - Matcher matcher = null; - switch (message_section) { - case HEAD: - messageInfo.editHeadParam(isRequest, param_name, new_value); - byte[] message = messageInfo.getMessage(isRequest, helpers); - messageInfo.setHost(new_value); // this should be set when the message is converted to the burp class - return message; - - case BODY: - if (!isBodyRegex) { - pattern = Pattern.compile("(?<=" + param_name + "=)[^$\\n& ]*"); - } else { - pattern = Pattern.compile(param_name); - } - - matcher = pattern.matcher(new String(messageInfo.getBody(isRequest))); - messageInfo.setBody(isRequest, matcher.replaceAll(new_value)); - //Automatically update content-lenght - return messageInfo.getMessage(isRequest, helpers); - - case URL: - if (!isRequest) { - throw new ParsingException("Encoding URL in response"); - } - String url_header = messageInfo.getUrlHeader(); - - pattern = Pattern.compile(param_name + "=[^& ]*((?=&)|(?= ))"); - matcher = pattern.matcher(url_header); - - messageInfo.setUrlHeader(matcher.replaceAll(param_name + "=" + new_value)); // problema - - return messageInfo.getMessage(isRequest, helpers); - } - return null; - } - - public static byte[] editMessageParam(IExtensionHelpers helpers, - String param_name, - Utils.DecodeOperationFrom decodeOperationFrom, - HTTPReqRes messageInfo, - boolean isRequest, - String new_value, - boolean isBodyRegex) throws ParsingException { - - Utils.MessageSection ms = null; - - switch (decodeOperationFrom) { - case HEAD: - ms = MessageSection.HEAD; - break; - case BODY: - ms = MessageSection.BODY; - break; - case URL: - ms = MessageSection.URL; - break; - case JWT_HEADER: - case JWT_PAYLOAD: - case JWT_SIGNATURE: - throw new ParsingException("invalid from section in decode operation should be a message section"); - } - - return editMessageParam( - helpers, - param_name, - ms, - messageInfo, - isRequest, - new_value, - isBodyRegex - ); - } - - /** - * Given a name, returns the corresponding variable - * - * @param name the name of the variable - * @return the Var object - * @throws ParsingException if the variable cannot be found - */ - public static Var getVariableByName(String name, GUI mainPane) throws ParsingException { - synchronized (mainPane.lock) { - for (Var act : mainPane.act_test_vars) { - if (act.name.equals(name)) { - return act; - } - } - } - throw new ParsingException("variable not defined"); - } - - /** - * Finds the parent div of an http element - * - * @param in the http element in xpath format - * @return the xpath of the parent div - * @throws ParsingException if no parent div present or input is malformed - */ - public static String findParentDiv(String in) throws ParsingException { - String[] split1 = in.split("="); - if (split1.length != 2) { - throw new ParsingException("invalid input \"" + in + "\" for finding parent div"); - } - String[] split = split1[1].split("/"); - if (split.length == 0) { - return in; - } - - int cut_indx = -1; - - //-2 because if the last element is a div i don't take it, otherwise is not a div, so i don't take it - for (int i = split.length - 2; i > 0; i--) { - if (split[i].contains("div")) { - cut_indx = i; - break; - } - } - if (cut_indx == -1) return in; - - String res = split1[0] + "="; - - for (int i = 1; i <= cut_indx; i++) { - if (i == cut_indx) { - // removes the index of the div element - res += "/" + split[i].replaceAll("\\[.*\\]", ""); - } else { - res += "/" + split[i]; - } - } - return res; - } - - /** - * @param action - * @param content - * @param j_path - * @param mainPane - * @param save_as - * @return - */ - public static String editJson(Utils.Jwt_action action, - String content, - String j_path, - GUI mainPane, - String save_as, - String newValue) throws PathNotFoundException { - Object document = Configuration.defaultConfiguration().jsonProvider().parse(content); - JsonPath jsonPath = JsonPath.compile(j_path); - - switch (action) { - case REMOVE: - document = jsonPath.delete(document, Configuration.defaultConfiguration()); - break; - case EDIT: - case ADD: - document = jsonPath.set(document, newValue, Configuration.defaultConfiguration()); - //TODO: check if set also adds in case it is not found - break; - case SAVE: - Var v = new Var(); - v.name = save_as; - v.isMessage = false; - v.value = JsonPath.read(content, j_path); //TODO could rise errors - synchronized (mainPane.lock) { - mainPane.act_test_vars.add(v); - } - break; - } - return Configuration.defaultConfiguration().jsonProvider().toJson(document); //basically converts to string - } - - public enum CheckIn { - // standard message - HEAD, - BODY, - URL, - // jwt - JWT_HEADER, - JWT_PAYLOAD, - JWT_SIGNATURE; - - public static CheckIn fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "head": - return HEAD; - case "body": - return BODY; - case "url": - return URL; - case "header": - return JWT_HEADER; - case "payload": - return JWT_PAYLOAD; - case "signature": - return JWT_SIGNATURE; - default: - throw new ParsingException("invalid in '" + input + "' for check"); - } - } else { - throw new NullPointerException(); - } - } - } - - public enum DecodeOperationFrom { - // standard message - HEAD, - BODY, - URL, - // jwt - JWT_HEADER, - JWT_PAYLOAD, - JWT_SIGNATURE; - - public static DecodeOperationFrom fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "head": - return HEAD; - case "body": - return BODY; - case "url": - return URL; - case "jwt header": - return JWT_HEADER; - case "jwt payload": - return JWT_PAYLOAD; - case "jwt signature": - return JWT_SIGNATURE; - default: - throw new ParsingException("invalid decode operation from '" + input + "'"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * An enum representing the possible message sections - */ - public enum MessageSection { - HEAD, - BODY, - URL, - RAW; - - /** - * Function that given a message section in form of String, returns the corresponding MessageSection enum value - * - * @param input the input string - * @return the MessageSection enum value - * @throws ParsingException if the input does not correspond to any of the possible messagesections - */ - public static MessageSection fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "head": - return HEAD; - case "body": - return BODY; - case "url": - return URL; - case "raw": - return RAW; - default: - throw new ParsingException("message section not valid"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * enum containing all the possible check operations - */ - public enum CheckOps { - IS, - IS_NOT, - CONTAINS, - NOT_CONTAINS, - IS_PRESENT, - IS_NOT_PRESENT; - - /** - * Function that given a String, returns the corresponding CheckOps enum's value - * - * @param input the input string - * @return the CheckOps enum value - * @throws ParsingException if the input string does not correspond to any of the possible check operations - */ - public static CheckOps fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "is": - return IS; - case "is not": - return IS_NOT; - case "contains": - return CONTAINS; - case "not contains": - return NOT_CONTAINS; - default: - throw new ParsingException("invalid check operation"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * Enum containing all the possible Active operation actions - */ - public enum Action { - INTERCEPT, - VALIDATE; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static Action fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "intercept": - return INTERCEPT; - case "validate": - return VALIDATE; - default: - throw new ParsingException("invalid check operation"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * Enum containing all the possible session operation actions - */ - public enum SessionAction { - START, - PAUSE, - RESUME, - STOP, - CLEAR_COOKIES; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static SessionAction fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "start": - return START; - case "pause": - return PAUSE; - case "resume": - return RESUME; - case "stop": - return STOP; - case "clear cookies": - return CLEAR_COOKIES; - default: - throw new ParsingException("invalid Session action"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * Enum that contains all the possible action to do after a message is received - */ - public enum Then { - FORWARD, - DROP; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static Then fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "forward": - return FORWARD; - case "drop": - return DROP; - default: - throw new ParsingException("invalid check operation"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * All the possible actions of a MessageOperation - */ - public enum MessageOperationActions { - REMOVE_PARAMETER, - REMOVE_MATCH_WORD, - EDIT, - EDIT_REGEX, - ADD, - SAVE, - SAVE_MATCH; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static MessageOperationActions fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "remove parameter": - return REMOVE_PARAMETER; - case "remove match word": - return REMOVE_MATCH_WORD; - case "edit": - return EDIT; - case "edit regex": - return EDIT_REGEX; - case "add": - return ADD; - case "save": - return SAVE; - case "save match": - return SAVE_MATCH; - default: - throw new ParsingException("invalid check operation"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * The result type of (also the oracle) of an Active test - */ - public enum ResultType { - CORRECT_FLOW, - INCORRECT_FLOW, - ASSERT_ONLY; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static ResultType fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "correct": - return CORRECT_FLOW; - case "incorrect": - return INCORRECT_FLOW; - case "assert_only": - return ASSERT_ONLY; - default: - throw new ParsingException("invalid result"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * The possible encodings to be used - */ - public enum Encoding { - BASE64, - URL, - DEFLATE; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static Encoding fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "base64": - return BASE64; - case "url": - return URL; - case "deflate": - return DEFLATE; - default: - throw new ParsingException("invalid encoding"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * The possible types of messageOps - */ - public enum MessageOpType { - HTTP, - GENERATE_POC; - - /** - * From a string get the corresponding enum value - * - * @param input the string - * @return the enum value - * @throws ParsingException if the input is malformed - */ - public static MessageOpType fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "http": - return HTTP; - case "generate_poc": - return GENERATE_POC; - default: - throw new ParsingException("invalid message Op Type"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * Used to specify the type of decoded content, only when that content has to be edited. - */ - public enum DecodeOpType { - JWT, - NONE, - XML; - - public static DecodeOpType fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "jwt": - return JWT; - case "xml": - return XML; - default: - throw new ParsingException("invalid message Op Type"); - } - } else { - throw new NullPointerException(); - } - } - } - - public enum ContentType { - JSON, - HTTP; - - public static ContentType fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "json": - return JSON; - case "http": - return HTTP; - default: - throw new ParsingException("invalid content type " + input); - } - } - throw new ParsingException("invalid content type"); - } - } - - /** - * The possible XML actions are the ones described in this enum - */ - public enum XmlAction { - ADD_TAG, - ADD_ATTR, - EDIT_TAG, - EDIT_ATTR, - REMOVE_TAG, - REMOVE_ATTR, - SAVE_TAG, - SAVE_ATTR; - - /** - * From a string get the corresponding value - * - * @param input the input string - * @return the enum value - * @throws ParsingException if the string does not correspond to any of the values - */ - public static XmlAction fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "add tag": - return ADD_TAG; - case "add attribute": - return ADD_ATTR; - case "edit tag": - return EDIT_TAG; - case "edit attribute": - return EDIT_ATTR; - case "remove tag": - return REMOVE_TAG; - case "remove attribute": - return REMOVE_ATTR; - case "save tag": - return SAVE_TAG; - case "save attribute": - return SAVE_ATTR; - default: - throw new ParsingException("invalid xml action"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * Defines the possible actions to be done on a decoded parameter interpreted as plain text - */ - public enum TxtAction { - REMOVE, - EDIT, - ADD, - SAVE; - - /** - * From a string get the corresponding value - * - * @param input the input string - * @return the enum value - * @throws ParsingException if the string does not correspond to any of the values - */ - public static TxtAction fromString(String input) throws ParsingException { - if (input != null) { - switch (input) { - case "txt remove": - return REMOVE; - case "txt edit": - return EDIT; - case "txt add": - return ADD; - case "txt save": - return SAVE; - default: - throw new ParsingException("invalid xml action"); - } - } else { - throw new NullPointerException(); - } - } - } - - /** - * Defines the possible JWT token sections - */ - public enum Jwt_section { - HEADER, - PAYLOAD, - SIGNATURE; - - /** - * Get the JWT section enum value from a string - * - * @param s the string to parse - * @return the enum value - * @throws ParsingException if the string is invalid - */ - public static Jwt_section getFromString(String s) throws ParsingException { - switch (s) { - case "header": - return HEADER; - case "payload": - return PAYLOAD; - case "signature": - return SIGNATURE; - default: - throw new ParsingException("Invalid jwt section"); - } - } - } - - /** - * Defines the possible actions to be done on a JWT token - */ - public enum Jwt_action { - REMOVE, - EDIT, - ADD, - SAVE - } - - /** - * Defines the action of a session action - */ - public enum SessAction { - CLICK, - OPEN, - TYPE, - SNAPSHOT, - DIFF, - EQUALS, - WAIT, - SET_VAR, - CLEAR_COOKIES, - ASSERT_CLICKABLE, - ASSERT_NOT_CLICKABLE, - ASSERT_VISIBLE, - ASSERT_NOT_VISIBLE, - ASSERT_ELEM_CONTENT_IS, - ASSERT_ELEM_CONTENT_HAS, - ASSERT_ELEM_CLASS_IS, - ASSERT_ELEM_CLASS_HAS, - ASSERT_ELEM_HAS_ATTRIBUTE, - ASSERT_ELEM_NOT_HAS_ATTRIBUTE, - ALERT; - - /** - * Get a session action enum value from a string - * - * @param s the string - * @return the enum value - * @throws ParsingException if the string is invalid - */ - public static SessAction getFromString(String s) throws ParsingException { - switch (s) { - case "assert click": - case "click": - return CLICK; - case "open": - case "assert open": // just an alias of open - return OPEN; - case "type": - return TYPE; - case "snapshot": - return SNAPSHOT; - case "diff": - return DIFF; - case "equals": - return EQUALS; - case "wait": - return WAIT; - case "set var": - return SET_VAR; - case "clear cookies": - return CLEAR_COOKIES; - case "assert clickable": - return ASSERT_CLICKABLE; - case "assert not clickable": - return ASSERT_NOT_CLICKABLE; - case "assert visible": - return ASSERT_VISIBLE; - case "assert not visible": - return ASSERT_NOT_VISIBLE; - case "assert element content is": - return ASSERT_ELEM_CONTENT_IS; - case "assert element content has": - return ASSERT_ELEM_CONTENT_HAS; - case "assert element class is": - return ASSERT_ELEM_CLASS_IS; - case "assert element class has": - return ASSERT_ELEM_CLASS_HAS; - case "assert element has attribute": - return ASSERT_ELEM_HAS_ATTRIBUTE; - case "assert element not has attribute": - return ASSERT_ELEM_NOT_HAS_ATTRIBUTE; - case "alert": - return ALERT; - default: - throw new ParsingException("Invalid session action \"" + s + "\""); - } - } - } - - /** - * Defines the action of a session operation - */ - public enum SessOperationAction { - SAVE, - INSERT, - MARKER, - REMOVE - } - - /** - * Defines the target of a session operation. - * Is it better to use js or just build a form? if a form is used, body has to be interpreted - */ - public enum SessOperationTarget { - LAST_ACTION, - LAST_ACTION_ELEM, - LAST_ACTION_ELEM_PARENT, - LAST_CLICK, - LAST_CLICK_ELEM, - LAST_CLICK_ELEM_PARENT, - LAST_OPEN, - LAST_OPEN_ELEM, - LAST_URL, - ALL_ASSERT, - TRACK; - - /** - * Parse a string containing a session operation target - * - * @param s the string to parse - * @throws ParsingException if the string is malformed, or no session operation target is found - */ - public static SessOperationTarget getFromString(String s) throws ParsingException { - - if (s.contains(".")) { - String[] splitted; - splitted = s.split("\\."); - String left = splitted[0]; - boolean parent = false; - if (splitted.length == 3) { - if (splitted[2].equals("parent")) { - parent = true; - } - } - - switch (s) { - case "last_action.elem": - case "last_action.elem.parent": - return parent ? LAST_ACTION_ELEM_PARENT : LAST_ACTION_ELEM; - case "last_click.elem": - case "last_click.elem.parent": - return parent ? LAST_CLICK_ELEM_PARENT : LAST_CLICK_ELEM; - case "last_open.elem": - return LAST_OPEN_ELEM; - case "last_url": - return LAST_URL; - case "all_assert": - return ALL_ASSERT; - default: - throw new ParsingException("invalid target in session operation"); - } - } else { - switch (s) { - case "track": - return TRACK; - case "last_action": - return LAST_ACTION; - case "last_click": - return LAST_CLICK; - case "last_open": - return LAST_OPEN; - case "last_url": - return LAST_URL; - case "all_assert": - return ALL_ASSERT; - default: - throw new ParsingException("invalid target in session operation"); - } - } - } - } -} diff --git a/tool/src/test/java/Checks_Test.java b/tool/src/test/java/Checks_Test.java index 4a177a5..b2638b1 100644 --- a/tool/src/test/java/Checks_Test.java +++ b/tool/src/test/java/Checks_Test.java @@ -30,7 +30,7 @@ public Check initCheck_json(String check_str) throws ParsingException { Check c = new Check(new JSONObject(check_str)); DecodeOperation_API dopapi = new DecodeOperation_API(); - dopapi.type = Utils.DecodeOpType.JWT; + dopapi.type = DecodeOperation.DecodeOpType.JWT; dopapi.jwt_header = input; c.loader(dopapi); diff --git a/tool/src/test/java/DecodeOperation_Test.java b/tool/src/test/java/DecodeOperation_Test.java index 28a3963..67e53d9 100644 --- a/tool/src/test/java/DecodeOperation_Test.java +++ b/tool/src/test/java/DecodeOperation_Test.java @@ -1,6 +1,5 @@ import migt.DecodeOperation; import migt.ParsingException; -import migt.Utils; import org.json.JSONObject; import org.junit.jupiter.api.Test; @@ -51,12 +50,12 @@ public class DecodeOperation_Test { void test_parse() throws ParsingException { DecodeOperation dop = new DecodeOperation(new JSONObject(input)); - assertEquals(Utils.DecodeOperationFrom.URL, dop.from); + assertEquals(DecodeOperation.DecodeOperationFrom.URL, dop.from); assertEquals("asd", dop.decode_target); assertTrue(dop.decodeOperations.size() == 1); DecodeOperation child_dop = dop.decodeOperations.get(0); - assertEquals(Utils.DecodeOperationFrom.JWT_HEADER, child_dop.from); + assertEquals(DecodeOperation.DecodeOperationFrom.JWT_HEADER, child_dop.from); assertEquals("$.something", child_dop.decode_target); } @@ -64,7 +63,7 @@ void test_parse() throws ParsingException { void test_parse_w_checks() throws ParsingException { DecodeOperation dop = new DecodeOperation(new JSONObject(input_w_checks)); - assertEquals(Utils.DecodeOperationFrom.BODY, dop.from); + assertEquals(DecodeOperation.DecodeOperationFrom.BODY, dop.from); assertEquals(1, dop.checks.size()); } diff --git a/tool/src/test/java/GUI_Test.java b/tool/src/test/java/GUI_Test.java index 5f76db4..51f3486 100644 --- a/tool/src/test/java/GUI_Test.java +++ b/tool/src/test/java/GUI_Test.java @@ -1,7 +1,6 @@ import migt.ParsingException; import migt.Session; -import migt.Utils; -import org.json.JSONObject; +import migt.Tools; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -33,7 +32,7 @@ void test_batchPassivesFromSession() throws ParsingException { tests.get(6).sessions.get(0).name = "4"; tests.get(7).sessions.get(0).name = "1"; - HashMap> hm = Utils.batchPassivesFromSession(tests); + HashMap> hm = Tools.batchPassivesFromSession(tests); assertEquals(3, hm.get("1").size()); assertEquals(2, hm.get("2").size()); diff --git a/tool/src/test/java/JWT_Test.java b/tool/src/test/java/JWT_Test.java index 3175a53..5d04953 100644 --- a/tool/src/test/java/JWT_Test.java +++ b/tool/src/test/java/JWT_Test.java @@ -1,19 +1,9 @@ -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.security.Keys; import migt.JWT; import migt.ParsingException; -import migt.Utils; -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemWriter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import javax.crypto.SecretKey; - -import java.security.*; - import static org.junit.jupiter.api.Assertions.*; public class JWT_Test { diff --git a/tool/src/test/java/SessionTrackAction_Test.java b/tool/src/test/java/SessionTrackAction_Test.java index f3e7d71..f50516c 100644 --- a/tool/src/test/java/SessionTrackAction_Test.java +++ b/tool/src/test/java/SessionTrackAction_Test.java @@ -1,6 +1,6 @@ import migt.ParsingException; +import migt.SessionOperation; import migt.SessionTrackAction; -import migt.Utils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -15,19 +15,19 @@ void test_parseRawSessionAction() { try { s.parse_raw_action("open | https://www.facebook.com/ |"); - assertEquals(Utils.SessAction.OPEN, s.action); + assertEquals(SessionOperation.SessAction.OPEN, s.action); assertEquals("https://www.facebook.com/", s.elem); assertEquals("open | https://www.facebook.com/ |", s.toString()); s = new SessionTrackAction("click | xpath=/html/body/div[1]/div[3]/div/div[5]/div[1]/span[1] |"); - assertEquals(Utils.SessAction.CLICK, s.action); + assertEquals(SessionOperation.SessAction.CLICK, s.action); assertEquals("xpath=/html/body/div[1]/div[3]/div/div[5]/div[1]/span[1]", s.elem); assertEquals("xpath", s.elem_type); assertEquals("/html/body/div[1]/div[3]/div/div[5]/div[1]/span[1]", s.elem_source); assertEquals("click | xpath=/html/body/div[1]/div[3]/div/div[5]/div[1]/span[1] |", s.toString()); s = new SessionTrackAction("type | id=login | folafo9046@eoscast.com"); - assertEquals(Utils.SessAction.TYPE, s.action); + assertEquals(SessionOperation.SessAction.TYPE, s.action); assertEquals("id=login", s.elem); assertEquals("id", s.elem_type); assertEquals("login", s.elem_source); @@ -38,7 +38,7 @@ void test_parseRawSessionAction() { assertEquals("wait | 3000 |", s.toString()); s = new SessionTrackAction("equals | xpath=/html/body/div[1]/div[3]/div/div[5]/div[1]/span[1] |"); - assertEquals(Utils.SessAction.EQUALS, s.action); + assertEquals(SessionOperation.SessAction.EQUALS, s.action); assertEquals("equals | xpath=/html/body/div[1]/div[3]/div/div[5]/div[1]/span[1] |", s.toString()); } catch (ParsingException e) { assertEquals(1, 0); @@ -53,7 +53,7 @@ void testActionAsserts() throws ParsingException { in = "assert clickable | xpath=/html/body/div[1]/div[2]/div/div[2]/div/div/div/div[2]/div[2]/form/div[6]/div/div[3]/div/div[2]/div[1]/a |"; s.parse_raw_action(in); - assertEquals(s.action, Utils.SessAction.ASSERT_CLICKABLE); + assertEquals(s.action, SessionOperation.SessAction.ASSERT_CLICKABLE); assertEquals(s.toString(), in); s = new SessionTrackAction(); diff --git a/tool/src/test/java/Utils_Test.java b/tool/src/test/java/Utils_Test.java index 8b8ab09..e896159 100644 --- a/tool/src/test/java/Utils_Test.java +++ b/tool/src/test/java/Utils_Test.java @@ -30,7 +30,7 @@ void testBuildStringWithVars() throws ParsingException { String s = "test da aggiungere $questo$ e poi $qualcosaltro$"; String res = ""; try { - res = Utils.buildStringWithVars(vars, s); + res = Tools.buildStringWithVars(vars, s); } catch (ParsingException e) { e.printStackTrace(); } @@ -49,7 +49,7 @@ void testBuildStringWithVars() throws ParsingException { v4.value = "/link/a/caso"; vars.add(v4); - res = Utils.buildStringWithVars(vars, s); + res = Tools.buildStringWithVars(vars, s); assertEquals("open | https://www.youtube.com/link/a/caso |", res); } @@ -57,23 +57,23 @@ void testBuildStringWithVars() throws ParsingException { @DisplayName("Test find parent div") void testFindParentDiv() throws ParsingException { String in = "xpath=/html/body/div[3]/div[2]/div/div/div/div/div[3]/*[2]"; - String res = Utils.findParentDiv(in); + String res = Tools.findParentDiv(in); assertEquals("xpath=/html/body/div[3]/div[2]/div/div/div/div/div", res); assertThrows(ParsingException.class, () -> { - Utils.findParentDiv("https://www.facebook.com/"); + Tools.findParentDiv("https://www.facebook.com/"); }); assertThrows(ParsingException.class, () -> { - Utils.findParentDiv("https://www.ted.com/settings/account"); + Tools.findParentDiv("https://www.ted.com/settings/account"); }); in = "xpath=/html/body/div[2]/div/div[2]/form/div/span/span/button"; - res = Utils.findParentDiv(in); + res = Tools.findParentDiv(in); assertEquals("xpath=/html/body/div[2]/div/div[2]/form/div", res); in = "id=email"; - res = Utils.findParentDiv(in); + res = Tools.findParentDiv(in); assertEquals("id=email", res); }