Skip to content

Commit

Permalink
feat: added at_hash module
Browse files Browse the repository at this point in the history
  • Loading branch information
mattebit committed Dec 22, 2023
1 parent da3b4c5 commit ef55407
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 1 deletion.
106 changes: 106 additions & 0 deletions tool/src/main/java/migt/At_Hash.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package migt;

import org.apache.commons.codec.binary.Base64;
import org.json.JSONException;
import org.json.JSONObject;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
* Module used to check the correctness of the at_hash parameter inside of the id_token wrt to the released access_token
* https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
*/
public class At_Hash extends Module {

public At_Hash() {
}

@Override
public void loader(API api) {
if (!(api instanceof Operation_API)) {
throw new RuntimeException("Tried to load an api not supported in At_Hash module");
}
imported_api = api;
}

@Override
public void execute() {
if (imported_api == null) {
throw new RuntimeException("imported API is null in module At_Hash");
}

if (((Operation_API) imported_api).is_request) {
throw new RuntimeException("Expecting a response got request in At_Hash module");
}

// parse message body and take id_token and access_token values
String body = new String(((Operation_API) imported_api).message.getBody(false));

String id_token = "";
String access_token = "";

try {
JSONObject o = new JSONObject(body);
id_token = o.getString("id_token");
access_token = o.getString("access_token");
} catch (JSONException e) {
throw new RuntimeException("Invalid JSON in body");
}

// parse id_token jwt taking alg and at_hash parameters
String alg = "";
String at_hash = "";
try {
JWT j = new JWT();
j.parse(id_token);
JSONObject o = new JSONObject(j.header);
alg = o.getString("alg");
o = new JSONObject(j.payload);
at_hash = o.getString("at_hash");

} catch (ParsingException | JSONException e) {
System.out.println(e);
result = false;
return;
}

// select the hashing algorithm based on the ID_TOKEN alg header parameter
String hash_alg = alg.substring(1);
byte[] hashed;
try {
switch (hash_alg) {
case "S256":
hashed = MessageDigest.getInstance("SHA-256").digest(access_token.getBytes());
break;
case "S384":
hashed = MessageDigest.getInstance("SHA-384").digest(access_token.getBytes());
break;
case "S512":
hashed = MessageDigest.getInstance("SHA-512").digest(access_token.getBytes());
break;
default:
System.out.println("At_Hash module: unsupported hashing alg: " + alg);
result = false;
return;
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("At_Hash: Invalid algorithm selected to hash content");
}

// select the first 128 bits of the hash of the access token
byte[] left = Arrays.copyOfRange(hashed, 0, 16);

// base64url encode the previous value
String at_hash_generated = Base64.encodeBase64URLSafeString(left);

// remove "=" characters
at_hash_generated = at_hash_generated.replaceAll("=", "");

applicable = true; // this means that all the steps that precedes the check were accomplished correctly

// check previous value is equal to at_hash
result = at_hash_generated.equals(at_hash);
}
}
15 changes: 14 additions & 1 deletion tool/src/main/java/migt/Module.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import org.json.JSONObject;

import java.security.NoSuchAlgorithmException;

/**
* This class is the Parent class inherited by all modules. It provides some methods and parameters to be
* used by other classes
Expand All @@ -13,14 +15,18 @@ public class Module {
API api; // the api of this module
API imported_api; // the api imported from a previous module

/**
* When the module doesn't require any input
*/
public Module() {

}

/**
* Used when the module requires input by the user.
* Instantiate the module by parsing a JSONObject
*
* @param json_module
* @param json_module the json input for this module
*/
public Module(JSONObject json_module) {
// Parse
Expand Down Expand Up @@ -96,4 +102,11 @@ public <T extends Module> boolean setResult(T module) {
public boolean getResult() {
return this.result;
}

/**
* Execute this module and give a result
* @return the result of this module
*/
public void execute() {
}
}
19 changes: 19 additions & 0 deletions tool/src/main/java/migt/Operation.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package migt;

import burp.IInterceptedProxyMessage;
import org.checkerframework.checker.units.qual.A;
import org.json.JSONArray;
import org.json.JSONObject;

Expand Down Expand Up @@ -39,6 +40,8 @@ public class Operation extends Module {
private Action action;
private String session;
private SessionOperation.SessionAction sessionAction;
// submodules
private boolean at_hash_verify;

/**
* Instantiate an operation
Expand Down Expand Up @@ -145,6 +148,11 @@ public Operation(JSONObject operation_json,
if (operation_json.has("edit operations")) {
editOperations = Tools.parseEditsFromJSON(operation_json.getJSONArray("edits"));
}

//Other modules
if (operation_json.has("at_hash_verify")) {
at_hash_verify = operation_json.getBoolean("at_hash_verify");
}
}

private void init() {
Expand Down Expand Up @@ -461,6 +469,17 @@ public void execute() {
executeChecks(this, api.vars);
if (!applicable | !result)
return;

if (at_hash_verify) {
At_Hash at = new At_Hash();
at.loader(api);
at.execute();
setResult(at);
if (!applicable | ! result) {
return;
}
}

// TODO: move this here instead of Execute Actives
//executeSessionOps(, api.vars);
//if (!applicable | !result)
Expand Down
59 changes: 59 additions & 0 deletions tool/src/test/java/At_Hash_Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import migt.At_Hash;
import migt.HTTPReqRes;
import migt.Operation_API;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class At_Hash_Test {

public HTTPReqRes init_message_token_resp() {
String raw= "HTTP/1.1 200 OK\r\n" +
"Date: Fri, 22 Dec 2023 13:12:13 GMT\r\n" +
"Server: WSGIServer/0.2 CPython/3.10.13\r\n" +
"Content-Type: application/json\r\n" +
"X-Frame-Options: DENY\r\n" +
"Content-Length: 2037\r\n" +
"X-Content-Type-Options: nosniff\r\n" +
"Referrer-Policy: same-origin\r\n" +
"Cross-Origin-Opener-Policy: same-origin\r\n" +
"\r\n";


List<String> headers = new ArrayList<>();

Collections.addAll(headers, raw.split("\r\n"));

int body_offset = raw.length();

raw += "{\"access_token\": \"eyJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlBkMk45LVRael9BV1MzR0ZDa29ZZFJhWFhsczhZUGh4X2RfRXo3SndqUUkifQ.eyJpc3MiOiJodHRwOi8vY2llLXByb3ZpZGVyLm9yZzo4MDAyL29pZGMvb3AiLCJzdWIiOiIyMmE4M2FhZmRlOWUyYzhkZmU2MzM1NTk3ZDk1MTNlMzYzMDdhOWI0NjI1NjVkYTg4MzM5ZTQzMDEyOGE0ODlhIiwiYXVkIjpbImh0dHA6Ly9jaWUtcHJvdmlkZXIub3JnOjgwMDIvb2lkYy9vcCIsIi9vaWRjL29wL3VzZXJpbmZvIl0sImNsaWVudF9pZCI6Imh0dHA6Ly9yZWx5aW5nLXBhcnR5Lm9yZzo4MDAxIiwic2NvcGUiOiJvcGVuaWQgb2ZmbGluZV9hY2Nlc3MiLCJqdGkiOiJmMTA0MWMxYi1hNDYyLTQ3ZWYtOTJjNi0zYWU0ZDNkZTgzMjIiLCJleHAiOjE3MDMyNTI3MTMsImlhdCI6MTcwMzI1MDczM30.bSlYNNyB8zdvE4M-9aiMEeI9NAsd12w47BCb_5ywZqLZMEJ06NYSHzhnJKzonh2TW32I9VFeB8ZxlyTmiFpaLuTm4onN2FfHIWeWYgwwAo-0JgUdjNGS07Vy4EkqZeFChDJCcI4uUriIFEG4u2dnTILNjJC1qcjA3CIlPn7kz9RkDfGw4zAFlOQZ9oVJj5LFUHfB7oDem2z0uJehw5gXHEVBi0hcA1Lj10i8rVuTqhRfCoOdxZwBuTq7eH6z6jCSIplyPIhVqY-dhGQrDvR_tMY4Ulz7Xd0EVjvs09H9QT1tDz9e8WNTF_UbQV8nEaTkbOzN9AC9C0JdJ76O0kH_yg\", \"id_token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6IlBkMk45LVRael9BV1MzR0ZDa29ZZFJhWFhsczhZUGh4X2RfRXo3SndqUUkifQ.eyJzdWIiOiIyMmE4M2FhZmRlOWUyYzhkZmU2MzM1NTk3ZDk1MTNlMzYzMDdhOWI0NjI1NjVkYTg4MzM5ZTQzMDEyOGE0ODlhIiwibm9uY2UiOiJFNzdKenN0NDNNdjNsUmNyZ2lSRW01U3lRNjNCMTd4VyIsImF0X2hhc2giOiJhVDVmd21tNmFaZmdoTUpYNGZ0Q0N3IiwiY19oYXNoIjoiZm8wVHB3cDRMVm03MmhwcFNsVVpLUSIsImF1ZCI6WyJodHRwOi8vcmVseWluZy1wYXJ0eS5vcmc6ODAwMSJdLCJpc3MiOiJodHRwOi8vY2llLXByb3ZpZGVyLm9yZzo4MDAyL29pZGMvb3AiLCJhY3IiOiJodHRwczovL3d3dy5zcGlkLmdvdi5pdC9TcGlkTDIiLCJqdGkiOiJiYjE5ZGUwYi0xNGQ3LTQzNGEtOTVmNS1jMWRlNWNhNzhkNWQiLCJmYW1pbHlfbmFtZSI6Im1hcmFkb25hIiwiZ2l2ZW5fbmFtZSI6InBlcHBlIiwiZXhwIjoxNzAzMjUyNzEzLCJpYXQiOjE3MDMyNTA3MzN9.h6cUctsaauPpwgPlL_S5A1v_FxWsgAPh1lppizSOwmw0k0r8XlA8EhxXF7NuTG0fyF-TvIR-XzjOovZyv7nfp2uTExzwjBK36S9qixRlLdZeAP5keMTzBGQRAvRzf3xCfdbo9Hz3wdFVAaZL4owbFZJrEf79j6bkJ7EYWPpaxgT2iWoaBDLNBh9cNhRAisBjpKF7Pg9Qjcgh06JBWTdcaGXxt7RITNhh03_kXNmHXc1tNyHqBMhUfPpdDgn0qzbhRm4lRPKg93sMvLTpyETsPsTiVrlBZqZpR-0DpSDRWibCw40vcPS0fbRgHZUWmrxPiyqh9e7hr3MM2Gbejg8THg\", \"token_type\": \"Bearer\", \"expires_in\": 1980, \"scope\": \"openid offline_access\"}";
byte[] raw_b = raw.getBytes(StandardCharsets.UTF_8);

HTTPReqRes message = new HTTPReqRes(null, raw_b);
message.body_offset_resp = body_offset;
message.setHeaders(false, headers);
message.isResponse = true;
message.isRequest = false;

return message;
}

@Test
public void test_At_Hash() throws NoSuchAlgorithmException {
HTTPReqRes test_message = init_message_token_resp();

At_Hash ah = new At_Hash();

Operation_API o = new Operation_API(test_message, false);

ah.loader(o);
ah.execute();
assertTrue(ah.getResult());
}
}

0 comments on commit ef55407

Please sign in to comment.