Skip to content

Commit

Permalink
Version 1.2-stable
Browse files Browse the repository at this point in the history
  • Loading branch information
ThisIsLibra committed Apr 2, 2021
1 parent 213e00b commit b7a872f
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 9 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>malwarepuller</groupId>
<artifactId>MalPull</artifactId>
<version>1.1-stable</version>
<version>1.2-stable</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
1 change: 1 addition & 0 deletions src/main/java/endpoints/IEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package endpoints;

/**
* The interface to use for all endpoints that are used
*
* @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*/
Expand Down
106 changes: 106 additions & 0 deletions src/main/java/endpoints/Triage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2021 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package endpoints;

import exceptions.SampleNotFoundException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONObject;

/**
* The class that is used to get a sample from Triage
*
* @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*/
public class Triage extends GenericEndpoint implements IEndpoint {

/**
* The API key for Triage
*/
private String key;

/**
* The HTTP client that sends out the request
*/
protected final OkHttpClient httpClient;

/**
* Creates an object to interact with the Triage endpoint
*
* @param key
*/
public Triage(String key) {
super("https://api.tria.ge/v0/", "Triage");
this.key = key;
httpClient = new OkHttpClient();
}

/**
* Retrieves the sample identifier from Triage that is required to download
* the sample
*
* @param hash SHA-256 hash of the sample to download
* @return sample identifier assigned by Triage
* @throws SampleNotFoundException if the sample cannot be found for any
* reason whatsoever
*/
public String getSampleId(String hash) throws SampleNotFoundException {
//Create the URL
String url = apiBase + "search?query=" + hash;
//Prepare the request with the API key
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + key)
.build();
//Execute the request
try (Response response = httpClient.newCall(request).execute()) {
//Check if the request was successful
if (response.isSuccessful()) {
//Parse the JSON response and extract the identifier
JSONObject object = new JSONObject(response.body().string());
JSONArray array = object.getJSONArray("data");
return array.getJSONObject(0).getString("id");
} else {
throw new SampleNotFoundException("Sample not present on Triage!");
}
} catch (Exception ex) {
throw new SampleNotFoundException("An exception occured when getting the sample id for Triage!");
}
}

/**
* Download the sample from the API
*
* @param hash SHA-256 hash of the sample to download
* @return the API's response, which is the raw file
* @throws SampleNotFoundException if the sample cannot be found
*/
public byte[] getSample(String hash) throws SampleNotFoundException {
//Create the URL
String sampleId = getSampleId(hash);
String url = apiBase + "samples/" + sampleId + "/sample";
//Prepare the request with the API key
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + key)
.build();
//Return the value of the direct download link
return downloader.get(request);
}
}
4 changes: 3 additions & 1 deletion src/main/java/endpoints/VirusTotal.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import okhttp3.Request;

/**
* The class to get a sample from VirusTotal.
*
* @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*/
Expand All @@ -31,7 +32,8 @@ public class VirusTotal extends GenericEndpoint implements IEndpoint {
private String key;

/**
* Creates an object to interact with the VirusTotal endpoint, based on API version 2
* Creates an object to interact with the VirusTotal endpoint, based on API
* version 2
*
* @param key
*/
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/malpull/ArgumentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class ArgumentHandler {

/**
* Parses the arguments into an Arguments object. Stops MalPull upon the
* occurence of an exception and prints a help message for the user
* occurrence of an exception and prints a help message for the user
*
* @param args the arguments to parse
* @return the parsed arguments
Expand Down Expand Up @@ -77,6 +77,7 @@ public static Arguments handle(String[] args) {
String malwareBazaarKey = null;
String malShareKey = null;
String virusTotalKey = null;
String triageKey = null;
//Iterate through all keys, note that the endpoint prefix is case insensitive
for (String key : keys) {
if (key.toLowerCase().startsWith("koodous=".toLowerCase())) {
Expand All @@ -87,6 +88,8 @@ public static Arguments handle(String[] args) {
malShareKey = key.substring("malshare=".length(), key.length());
} else if (key.toLowerCase().startsWith("virustotal=".toLowerCase())) {
virusTotalKey = key.substring("virustotal=".length(), key.length());
} else if (key.toLowerCase().startsWith("triage=".toLowerCase())) {
triageKey = key.substring("triage=".length(), key.length());
}
}

Expand All @@ -103,7 +106,7 @@ public static Arguments handle(String[] args) {
}

//Return the parsed arguments
return new Arguments(hashes, path.getAbsolutePath(), threadCount, koodousKey, malwareBazaarKey, malShareKey, virusTotalKey);
return new Arguments(hashes, path.getAbsolutePath(), threadCount, koodousKey, malwareBazaarKey, malShareKey, virusTotalKey, triageKey);
}

/**
Expand Down Expand Up @@ -160,7 +163,7 @@ private static String filterPath(String path) {
* Prints the program's usage
*/
private static void printUsage() {
System.out.println("This tool downloads samples from MalShare, MalwareBazaar, Koodous, and VirusTotal based on given MD-5, SHA-1, or SHA-256 hashes.");
System.out.println("This tool downloads samples from MalShare, MalwareBazaar, Koodous, VirusTotal, and Hatching Triage based on given MD-5, SHA-1, or SHA-256 hashes.");
System.out.println("The sample is written to the given output directory. API Keys for any of the used services is required.");
System.out.println("Once all samples are downloaded, the hashes that couldn't be found will be listed.");
System.out.println("For detailed information on the usage of MalPull, please visit https://maxkersten.nl/wordpress/projects/malpull/#usage");
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/malpull/Arguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public class Arguments {
*/
private String virusTotalKey;

/**
* The API key for Triage
*/
private String triageKey;

/**
* Creates an object that contains all parsed arguments
* @param hashes all loaded hashes
Expand All @@ -70,15 +75,17 @@ public class Arguments {
* @param malwareBazaarKey the API key for Malware Bazaar
* @param malShareKey the API key for MalShare
* @param virusTotalKey the API key for VirusTotal
* @param triageKey the API key for Triage
*/
public Arguments(Set<String> hashes, String outputPath, int threadCount, String koodousKey, String malwareBazaarKey, String malShareKey, String virusTotalKey) {
public Arguments(Set<String> hashes, String outputPath, int threadCount, String koodousKey, String malwareBazaarKey, String malShareKey, String virusTotalKey, String triageKey) {
this.hashes = hashes;
this.outputPath = outputPath;
this.threadCount = threadCount;
this.koodousKey = koodousKey;
this.malwareBazaarKey = malwareBazaarKey;
this.malShareKey = malShareKey;
this.virusTotalKey = virusTotalKey;
this.triageKey = triageKey;
}

/**
Expand Down Expand Up @@ -136,4 +143,12 @@ public String getMalShareKey() {
public String getVirusTotalKey() {
return virusTotalKey;
}

/**
* The API key of Triage, can be null if the API key is not used
* @return the API key
*/
public String getTriageKey() {
return triageKey;
}
}
11 changes: 8 additions & 3 deletions src/main/java/malpull/MalPull.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import endpoints.Koodous;
import endpoints.MalShare;
import endpoints.MalwareBazaar;
import endpoints.Triage;
import endpoints.VirusTotal;
import java.time.Instant;
import java.util.ArrayList;
Expand Down Expand Up @@ -103,6 +104,10 @@ public static void main(String[] args) {
IEndpoint virusTotal = new VirusTotal(arguments.getVirusTotalKey());
endpoints.add(virusTotal);
}
if (arguments.getTriageKey() != null) {
IEndpoint triage = new Triage(arguments.getTriageKey());
endpoints.add(triage);
}

//Create a download worker for the hash, with all configured endpoints embedded
DownloadWorker downloadWorker = new DownloadWorker(endpoints, arguments.getOutputPath(), hash, count, hashes.size());
Expand All @@ -116,7 +121,7 @@ public static void main(String[] args) {
}
//Notify the user that all downloads are finished
System.out.println("");
System.out.println("All downloads finished! The sample number count is not always printed ascending as the threads print the messages.");
System.out.println("All downloads finished! The sample number count is not always printed in ascending order, as the threads print the messages.");

//If some hashes could not be found, these are printed
if (missingHashes.size() > 0) {
Expand All @@ -128,7 +133,7 @@ public static void main(String[] args) {
//Get the time since the start of the downloading
String time = getDuration(start);
//Display the time that the download process took
System.out.println("\nDownloaded " + hashes.size() + " samples in " + time + "!");
System.out.println("\nDownloaded " + (hashes.size() - missingHashes.size()) + " samples in " + time + "!");
//Exit the program explicitly, as it sometimes remains open in some edge cases
System.exit(0);
}
Expand Down Expand Up @@ -169,6 +174,6 @@ public static synchronized void addMissingHash(String missingHash) {
* Prints the version information, together with an additional newline
*/
private static void printVersionInformation() {
System.out.println("MalPull version 1.1-stable by Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]\n");
System.out.println("MalPull version 1.2-stable by Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]\n");
}
}
Binary file not shown.

0 comments on commit b7a872f

Please sign in to comment.