From a490426f9df3c556c20b45a36708fb605191b960 Mon Sep 17 00:00:00 2001 From: Andrey Rainchik Date: Wed, 4 Dec 2019 15:31:23 -0600 Subject: [PATCH] Using AWS SDK for assumeRole operations --- build.gradle | 6 +- src/main/java/burp/BurpExtender.java | 137 +++++++------------- src/main/java/burp/HttpRequestResponse.java | 63 --------- src/main/java/burp/Utility.java | 41 ------ 4 files changed, 51 insertions(+), 196 deletions(-) delete mode 100644 src/main/java/burp/HttpRequestResponse.java diff --git a/build.gradle b/build.gradle index 0088de7..f96e81d 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,6 @@ version '1.0-SNAPSHOT' apply plugin: 'java' - repositories { mavenCentral() } @@ -12,7 +11,12 @@ dependencies { compile 'com.google.guava:guava:23.2-jre' compile 'com.intellij:forms_rt:7.0.3' compile 'javax.xml.bind:jaxb-api:2.3.0' + // https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-sts + compile group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.11.683' testCompile group: 'junit', name: 'junit', version: '4.12' + implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.228') + implementation 'com.amazonaws:aws-java-sdk-sts' + testImplementation group: 'junit', name: 'junit', version: '4.11' } def mainClassName = "com.netspi.awssigner.Main" diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index d858e44..adcd1bc 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -1,5 +1,12 @@ package burp; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.auth.BasicSessionCredentials; +import com.amazonaws.services.securitytoken.AWSSecurityTokenService; +import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; +import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; +import com.amazonaws.services.securitytoken.model.AssumeRoleResult; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; import com.intellij.uiDesigner.core.Spacer; @@ -7,7 +14,6 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.BufferedReader; @@ -15,10 +21,9 @@ import java.io.FileReader; import java.io.PrintWriter; import java.util.HashMap; -import java.util.concurrent.*; +import java.util.Objects; public class BurpExtender implements IBurpExtender, ITab, IHttpListener { - private IBurpExtenderCallbacks callbacks; private IExtensionHelpers helpers; private PrintWriter pw; private JPanel panel; @@ -52,7 +57,6 @@ public class BurpExtender implements IBurpExtender, ITab, IHttpListener { @Override public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { - this.callbacks = callbacks; helpers = callbacks.getHelpers(); this.pw = new PrintWriter(callbacks.getStdout(), true); @@ -75,7 +79,7 @@ public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { } - public void createNewProfile() { + private void createNewProfile() { // Add another profile to the combo box, or add the add profile button if it's not already there. int boxSize = profileComboBox.getItemCount(); @@ -96,7 +100,7 @@ public void createNewProfile() { } } - public void clearProfile() { + private void clearProfile() { // Reset text fields this.accessKey.setText(""); this.secretKey.setText(""); @@ -109,7 +113,7 @@ public void clearProfile() { this.dynamicRegionAndService.setSelected(false); } - public void populateProfile(int profile) { + private void populateProfile(int profile) { this.accessKey.setText(this.profiles.get(profile)[ACCESS_KEY]); this.secretKey.setText(this.profiles.get(profile)[SECRET_KEY]); this.token.setText(this.profiles.get(profile)[TOKEN]); @@ -122,12 +126,11 @@ public void populateProfile(int profile) { } - public void createAndPopulateProfile(String[] details, String name) { + private void createAndPopulateProfile(String[] details, String name) { // Add another profile to the combo box, or add the add profile button if it's not already there. int boxSize = profileComboBox.getItemCount(); + // If there's nothing here, just add our add profile button if (boxSize == 0) { - - // If there's nothing here, just add our add profile button this.profileComboBox.addItem(new AWSSignerMenuItem("Add Profile", 0)); } else { for(int i = 0; i < boxSize; ++i) { @@ -152,24 +155,21 @@ public void createAndPopulateProfile(String[] details, String name) { } } - public void setupTab() { + private void setupTab() { // Set up profiles combobox - this.profiles = new HashMap(); + this.profiles = new HashMap<>(); createNewProfile(); createNewProfile(); - this.profileComboBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED && !justDeleted) { - int selectedProfile = ((AWSSignerMenuItem) e.getItem()).getProfileNumber(); - if (selectedProfile == 0) { - pw.println("Creating new profile..."); - createNewProfile(); - } else { - populateProfile(selectedProfile); - } + this.profileComboBox.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED && !justDeleted) { + int selectedProfile = ((AWSSignerMenuItem) e.getItem()).getProfileNumber(); + if (selectedProfile == 0) { + pw.println("Creating new profile..."); + createNewProfile(); + } else { + populateProfile(selectedProfile); } } }); @@ -187,7 +187,7 @@ public void mousePressed(MouseEvent e) { @Override public void mouseReleased(MouseEvent e) { - int profile = ((AWSSignerMenuItem) profileComboBox.getSelectedItem()).getProfileNumber(); + int profile = ((AWSSignerMenuItem) Objects.requireNonNull(profileComboBox.getSelectedItem())).getProfileNumber(); if (useDefaultProfile.isSelected()) { String[] profileToPut = new String[]{"", "", "", "", "", String.valueOf(useToken.isSelected()), @@ -257,7 +257,7 @@ public void mousePressed(MouseEvent e) { @Override public void mouseReleased(MouseEvent e) { - int profile = ((AWSSignerMenuItem) profileComboBox.getSelectedItem()).getProfileNumber(); + int profile = ((AWSSignerMenuItem) Objects.requireNonNull(profileComboBox.getSelectedItem())).getProfileNumber(); int index = profileComboBox.getSelectedIndex(); pw.println("Deleting profile " + profile + "..."); @@ -320,7 +320,7 @@ public void mousePressed(MouseEvent e) { @Override public void mouseReleased(MouseEvent e) { - int profile = ((AWSSignerMenuItem) profileComboBox.getSelectedItem()).getProfileNumber(); + int profile = ((AWSSignerMenuItem) Objects.requireNonNull(profileComboBox.getSelectedItem())).getProfileNumber(); Menu.setEnabledProfile(profile); } @@ -349,43 +349,28 @@ public void mousePressed(MouseEvent e) { @Override public void mouseReleased(MouseEvent e) { String[] profile = profiles.get(Menu.getEnabledProfile()); - IHttpService service = helpers.buildHttpService("sts.amazonaws.com", 443, true); - if(roleArn.getText().length() < 20) { - pw.println("Invalid role ARN"); - return; - } - byte[] signedRequest = Utility.assumeRole(roleArn.getText(), - profile[ACCESS_KEY], - profile[SECRET_KEY], - profile[TOKEN], - helpers, - pw, - service); - if(signedRequest == null) { - pw.println("Error in signing"); - return; - } - IHttpRequestResponse response = makeRequest(service, signedRequest); - if (response == null) { - pw.println("Error in sending request"); - return; - } - String[] creds = getCredsFromResponse(response); - if (creds == null) { - pw.println("Error retrieving credentials, check ARN name or permissions"); - return; + AWSSecurityTokenService stsClient; + if(profile[TOKEN].isEmpty()) { + BasicAWSCredentials awsCreds = new BasicAWSCredentials(profile[ACCESS_KEY], profile[SECRET_KEY]); + stsClient = AWSSecurityTokenServiceClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build(); + } else { + BasicSessionCredentials awsCreds = new BasicSessionCredentials(profile[ACCESS_KEY], profile[SECRET_KEY], profile[TOKEN]); + stsClient = AWSSecurityTokenServiceClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build(); } + AssumeRoleRequest assume = new AssumeRoleRequest().withRoleArn(roleArn.getText()).withRoleSessionName("testing"); + AssumeRoleResult result = stsClient.assumeRole(assume); + String[] details = new String[]{ - creds[0], // access key - creds[1], // secret key - "", // region - "", // service - creds[2], // session token - Boolean.toString(true), // use token - Boolean.toString(true), // use dynamic region and service - Boolean.toString(false), // use default credentials - ""}; // role ARN - int profileNum = ((AWSSignerMenuItem) profileComboBox.getSelectedItem()).getProfileNumber(); + result.getCredentials().getAccessKeyId(), // access key + result.getCredentials().getSecretAccessKey(), // secret key + "", // region + "", // service + result.getCredentials().getSessionToken(), // session token + Boolean.toString(true), // use token + Boolean.toString(true), // use dynamic region and service + Boolean.toString(false), // use default credentials + ""}; // role ARN + int profileNum = ((AWSSignerMenuItem) Objects.requireNonNull(profileComboBox.getSelectedItem())).getProfileNumber(); String[] save = profiles.get(profileNum); save[ARN] = roleArn.getText(); profiles.replace(profileNum, save); @@ -404,36 +389,6 @@ public void mouseExited(MouseEvent e) { }); } - private IHttpRequestResponse makeRequest(IHttpService service, byte[] request) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Callable callable = new Callable() { - @Override - public IHttpRequestResponse call() { - return callbacks.makeHttpRequest(service, request); - } - }; - Future future = executor.submit(callable); - executor.shutdown(); - try { - return future.get(); - } catch (Exception e) { - return null; - } - } - - private String[] getCredsFromResponse(IHttpRequestResponse response) { - String[] creds = {"", "", ""}; - String responseString = helpers.bytesToString(response.getResponse()); - if(responseString.contains("")) { - creds[0] = responseString.split("")[1].split("")[1].split("")[1].split(" headers = new ArrayList<>(); - headers.add("POST / HTTP/1.1"); - headers.add("Host: sts.amazonaws.com"); - headers.add("Accept-Encoding: gzip, deflate"); - headers.add("Content-Type: application/x-www-form-urlencoded; charset=utf-8"); - headers.add("User-Agent: aws-cli/1.16.132 Python/3.6.0 Windows/10 botocore/1.12.122 BurpAWSSigner"); - headers.add("X-Amz-Date: 20191122T201605Z"); - if(!token.isEmpty()) { - headers.add("X-Amz-Security-Token: " + token); - headers.add("Authorization: AWS4-HMAC-SHA256 Credential=" + accessKey + - "/20191122/us-east-1/sts/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token, Signature=testing"); - } else { - headers.add("Authorization: AWS4-HMAC-SHA256 Credential=" + accessKey + - "/20191122/us-east-1/sts/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=testing"); - } - headers.add("Connection: close"); - String body = "Action=AssumeRole&Version=2011-06-15&RoleArn="+arn+"&RoleSessionName=test"; - HttpRequestResponse request = new HttpRequestResponse(helpers.buildHttpMessage(headers, helpers.stringToBytes(body))); - request.setHttpService(service); - try { - byte[] signedRequest = signRequest(request, - helpers, - "sts", - "us-east-1", - accessKey, - secretKey, - token, - pw); - return signedRequest; - } catch (Exception e) { - return null; - } - } }