updates for file rep api

This commit is contained in:
Greg DiCristofaro 2023-07-21 09:19:48 -04:00
parent 541825472a
commit b7ab83efdd
21 changed files with 620 additions and 190 deletions

View File

@ -16,9 +16,10 @@ package com.basistech.df.cybertriage.autopsy.ctapi;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthenticatedRequestData;
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean;
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBeanResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResult;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil;
@ -65,16 +66,17 @@ public class CTApiDAO {
}
public AuthTokenResponse getAuthToken(String boostLicenseId) throws CTCloudException {
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted) throws CTCloudException {
AuthTokenRequest authTokenRequest = new AuthTokenRequest()
.setAutopsyVersion(getAppVersion())
.setRequestFileUpload(true)
.setBoostLicenseId(boostLicenseId);
.setRequestFileUpload(false)
.setBoostLicenseId(decrypted.getBoostLicenseId())
.setHostId(decrypted.getLicenseHostId());
return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
}
public List<FileReputationResult> getReputationResults(AuthenticatedRequestData authenticatedRequestData, List<String> md5Hashes) throws CTCloudException {
public List<CTCloudBean> getReputationResults(AuthenticatedRequestData authenticatedRequestData, List<String> md5Hashes) throws CTCloudException {
if (CollectionUtils.isEmpty(md5Hashes)) {
return Collections.emptyList();
}
@ -85,7 +87,7 @@ public class CTApiDAO {
.setToken(authenticatedRequestData.getToken())
.setHashes(md5Hashes);
FileReputationResponse resp = httpClient.doPost(CTCLOUD_SERVER_HASH_PATH, fileRepReq, FileReputationResponse.class);
CTCloudBeanResponse resp = httpClient.doPost(CTCLOUD_SERVER_HASH_PATH, fileRepReq, CTCloudBeanResponse.class);
return resp == null || resp.getItems() == null
? Collections.emptyList()
: resp.getItems();

View File

@ -29,6 +29,9 @@ public class AuthTokenRequest {
@JsonProperty("requestFileUpload")
private boolean requestFileUpload;
@JsonProperty("host_id")
private String hostId;
public String getAutopsyVersion() {
return autopsyVersion;
}
@ -56,4 +59,13 @@ public class AuthTokenRequest {
return this;
}
public String getHostId() {
return hostId;
}
public AuthTokenRequest setHostId(String hostId) {
this.hostId = hostId;
return this;
}
}

View File

@ -13,20 +13,24 @@
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochSecsDeserializer;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.ZonedDateTime;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.Instant;
/**
* POJO for an auth token response.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthTokenResponse extends AuthenticatedRequestData {
private final Long hashLookupCount;
private final Long hashLookupLimit;
private final Long fileUploadLimit;
private final Long fileUploadCount;
private final String fileUploadUrl;
private final ZonedDateTime expiration;
private final Instant expiration;
@JsonCreator
public AuthTokenResponse(
@ -37,7 +41,8 @@ public class AuthTokenResponse extends AuthenticatedRequestData {
@JsonProperty("fileUploadLimit") Long fileUploadLimit,
@JsonProperty("fileUploadCount") Long fileUploadCount,
@JsonProperty("fileUploadUrl") String fileUploadUrl,
@JsonProperty("expiration") ZonedDateTime expiration
@JsonDeserialize(using=InstantEpochSecsDeserializer.class)
@JsonProperty("expiration") Instant expiration
) {
this.token = token;
this.apiKey = apiKey;
@ -69,7 +74,7 @@ public class AuthTokenResponse extends AuthenticatedRequestData {
return fileUploadUrl;
}
public ZonedDateTime getExpiration() {
public Instant getExpiration() {
return expiration;
}
}

View File

@ -14,12 +14,14 @@
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* POJO for a boost license response object that is a part of the license
* response.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class BoostLicenseResponse {
private final String version;

View File

@ -0,0 +1,98 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2020 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
*
* @author rishwanth
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class CTCloudBean {
public static enum Status {
FOUND,
NOT_FOUND,
ERROR,
LIMITS_EXCEEDED,
BEING_SCANNED;
}
@Nonnull
@JsonProperty("malware")
private MalwareResultBean malwareResult;
@JsonProperty("correlation")
private CorrelationResultBean correlationResult;
@Nonnull
@JsonProperty("md5_hash")
private String md5HashValue;
@Nullable
@JsonProperty("sha1_hash")
private String sha1HashValue;
public String getMd5HashValue() {
return md5HashValue;
}
public String getSha1HashValue() {
return sha1HashValue;
}
public void setMd5HashValue(String md5HashValue) {
this.md5HashValue = md5HashValue;
}
public void setSha1HashValue(String sha1HashValue) {
this.sha1HashValue = sha1HashValue;
}
public MalwareResultBean getMalwareResult() {
return malwareResult;
}
public void setMalwareResult(MalwareResultBean malwareResult) {
this.malwareResult = malwareResult;
}
public CorrelationResultBean getCorrelationResult() {
return correlationResult;
}
public void setCorrelationResult(CorrelationResultBean correlationResult) {
this.correlationResult = correlationResult;
}
@Override
public String toString() {
return "CTCloudBean{"
+ "status=" + malwareResult.getStatus()
+ ", malwareDescription=" + malwareResult.getMalwareDescription()
+ ", score=" + malwareResult.getCTScore()
+ ", md5HashValue=" + md5HashValue
+ ", sha1HashValue=" + sha1HashValue
+ ", firstSeen=" + malwareResult.getFirstAnalyzedDate()
+ ", lastSeen=" + malwareResult.getLastAnalyzedDate()
+ ", statusDescription=" + malwareResult.getStatusDescription()
+ ", metadata=" + malwareResult.getMetadata()
+ '}';
}
}

View File

@ -14,24 +14,26 @@
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
/**
* Container for file reputation result list response.
*/
public class FileReputationResponse {
@JsonIgnoreProperties(ignoreUnknown = true)
public class CTCloudBeanResponse {
private final List<FileReputationResult> items;
private final List<CTCloudBean> items;
@JsonCreator
public FileReputationResponse(
@JsonProperty("items") List<FileReputationResult> items
public CTCloudBeanResponse(
@JsonProperty("items") List<CTCloudBean> items
) {
this.items = items;
}
public List<FileReputationResult> getItems() {
public List<CTCloudBean> getItems() {
return items;
}

View File

@ -0,0 +1,53 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nonnull;
@JsonIgnoreProperties(ignoreUnknown = true)
public class CTCloudCorrelationResultBean {
@JsonProperty("correlation")
private CorrelationResultBean correlationResult;
@Nonnull
@JsonProperty("signature")
private String signature;
public CorrelationResultBean getCorrelationResult() {
return correlationResult;
}
public void setCorrelationResult(CorrelationResultBean correlationResult) {
this.correlationResult = correlationResult;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
@Override
public String toString() {
return "CTCloudCorrelationResultBean{"
+ "correlationResult=" + correlationResult
+ ", signature=" + signature
+ '}';
}
}

View File

@ -0,0 +1,41 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
*
* @author rishwanth
*/
class CTCloudCostBean {
private final String provider;
private final Integer units;
public CTCloudCostBean(@JsonProperty("provider") String provider, @JsonProperty("units") Integer units) {
this.provider = provider;
this.units = units;
}
public String getProvider() {
return provider;
}
public Integer getUnits() {
return units;
}
}

View File

@ -0,0 +1,24 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2020 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
/**
*
* @author rishwanth
*/
public enum CorrelationFrequency {
UNIQUE,
RARE,
COMMON;
}

View File

@ -0,0 +1,46 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2020 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
*
* @author rishwanth
*/
public class CorrelationResultBean {
@JsonProperty("frequency")
private CorrelationFrequency frequency;
@JsonProperty("frequency_description")
private String frequencyDescription;
public CorrelationFrequency getFrequency() {
return frequency;
}
public String getFrequencyDescription() {
return frequencyDescription;
}
public void setFrequency(CorrelationFrequency frequency) {
this.frequency = frequency;
}
public void setFrequencyDescription(String frequencyDescription) {
this.frequencyDescription = frequencyDescription;
}
}

View File

@ -14,8 +14,9 @@
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochMillisDeserializer;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.MDYDateDeserializer;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.ZonedDateTimeDeserializer;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.Instant;
@ -24,6 +25,7 @@ import java.time.ZonedDateTime;
/**
* POJO for after encrypted boost license has been decrypted.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class DecryptedLicenseResponse {
private final String boostLicenseId;
@ -39,17 +41,16 @@ public class DecryptedLicenseResponse {
public DecryptedLicenseResponse(
@JsonProperty("boostLicenseId") String boostLicenseId,
@JsonProperty("licenseHostId") String licenseHostId,
@JsonDeserialize(using=MDYDateDeserializer.class)
@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
@JsonProperty("expirationDate") ZonedDateTime expirationDate,
@JsonProperty("hashLookups") Long hashLookups,
@JsonProperty("fileUploads") Long fileUploads,
@JsonDeserialize(using=InstantEpochMillisDeserializer.class)
@JsonDeserialize(using = InstantEpochMillisDeserializer.class)
@JsonProperty("activationTime") Instant activationTime,
@JsonProperty("product") String product,
@JsonProperty("limitType") String limitType,
@JsonProperty("l4jLicenseId") String l4jlicenseId,
@JsonProperty("ctLicenseId") String ctLicenseId
@JsonProperty("limitType") String limitType
// @JsonProperty("l4jLicenseId") String l4jlicenseId,
// @JsonProperty("ctLicenseId") String ctLicenseId
) {
this.boostLicenseId = boostLicenseId;
this.licenseHostId = licenseHostId;

View File

@ -1,123 +0,0 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.ZonedDateTime;
import java.util.List;
/**
* A file reputation result regarding malware status.
*/
public class FileReputationResult {
public static enum Status {
FOUND,
NOT_FOUND,
ERROR,
LIMITS_EXCEEDED,
BEING_SCANNED;
}
public enum CorrelationFrequency {
UNIQUE,
RARE,
COMMON;
}
private final String malwareDescription;
private final Status status;
private final CTScore score;
private final String md5Hash;
private final String sha1Hash;
private final ZonedDateTime firstScanDate;
private final ZonedDateTime lastScanDate;
private final List<MetadataLabel> metadata;
private final String statusDescription;
private final CorrelationFrequency frequency;
private final String frequencyDescription;
@JsonCreator
public FileReputationResult(
@JsonProperty("malwareDescription") String malwareDescription,
@JsonProperty("status") Status status,
@JsonProperty("score") CTScore score,
@JsonProperty("md5Hash") String md5Hash,
@JsonProperty("sha1Hash") String sha1Hash,
@JsonProperty("firstScanDate") ZonedDateTime firstScanDate,
@JsonProperty("lastScanDate") ZonedDateTime lastScanDate,
@JsonProperty("metadata") List<MetadataLabel> metadata,
@JsonProperty("statusDescription") String statusDescription,
@JsonProperty("frequency") CorrelationFrequency frequency,
@JsonProperty("frequencyDescription") String frequencyDescription
) {
this.malwareDescription = malwareDescription;
this.status = status;
this.score = score;
this.md5Hash = md5Hash;
this.sha1Hash = sha1Hash;
this.firstScanDate = firstScanDate;
this.lastScanDate = lastScanDate;
this.metadata = metadata;
this.statusDescription = statusDescription;
this.frequency = frequency;
this.frequencyDescription = frequencyDescription;
}
public String getMalwareDescription() {
return malwareDescription;
}
public Status getStatus() {
return status;
}
public CTScore getScore() {
return score;
}
public String getMd5Hash() {
return md5Hash;
}
public String getSha1Hash() {
return sha1Hash;
}
public ZonedDateTime getFirstScanDate() {
return firstScanDate;
}
public ZonedDateTime getLastScanDate() {
return lastScanDate;
}
public List<MetadataLabel> getMetadata() {
return metadata;
}
public String getStatusDescription() {
return statusDescription;
}
public CorrelationFrequency getFrequency() {
return frequency;
}
public String getFrequencyDescription() {
return frequencyDescription;
}
}

View File

@ -14,11 +14,13 @@
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Response POJO for request for license.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class LicenseResponse {
private final Boolean success;
private final Boolean hostChanged;

View File

@ -0,0 +1,165 @@
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2014 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.ZonedDateTimeDeserializer;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.ZonedDateTime;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
*
* @author rishwanth
*/
public class MalwareResultBean {
public static enum Status {
FOUND,
NOT_FOUND,
ERROR,
LIMITS_EXCEEDED,
BEING_SCANNED;
}
@Nullable
@JsonProperty("malware_description")
private String malwareDescription;
@Nonnull
@JsonProperty("status")
private Status status;
@Nonnull
@JsonProperty("score")
private String score;
private CTScore ctScore;
@Nullable
@JsonProperty("first_scan_date")
@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
private ZonedDateTime firstAnalyzedDate;
@Nullable
@JsonProperty("last_scan_date")
@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
private ZonedDateTime lastAnalyzedDate;
@JsonProperty("metadata")
private List<MetadataLabel> metadata;
@Nullable
@JsonProperty("status_description")
private String statusDescription;
@Nullable
@JsonProperty
private List<CTCloudCostBean> cost;
@JsonIgnore
public CTScore getCTScore() {
return ctScore;
}
public String getScore() {
return score;
}
public ZonedDateTime getFirstAnalyzedDate() {
return firstAnalyzedDate;
}
public ZonedDateTime getLastAnalyzedDate() {
return lastAnalyzedDate;
}
public List<MetadataLabel> getMetadata() {
if (metadata != null) {
return List.copyOf(metadata);
} else {
return List.of(); // empty list
}
}
public Status getStatus() {
return status;
}
public String getStatusDescription() {
return statusDescription;
}
public String getMalwareDescription() {
return malwareDescription;
}
public void setMalwareDescription(String malwareDescription) {
this.malwareDescription = malwareDescription;
}
public void setStatus(Status status) {
this.status = status;
}
public void setScore(String score) {
this.score = score;
switch(score) {
case "GOOD_HIGH":
this.ctScore = CTScore.NONE;
break;
case "GOOD_MEDIUM":
this.ctScore = CTScore.LIKELY_NONE;
break;
case "BAD_HIGH":
this.ctScore = CTScore.NOTABLE;
break;
case "BAD_MEDIUM":
this.ctScore = CTScore.LIKELY_NOTABLE;
break;
default:
this.ctScore = CTScore.UNKNOWN;
break;
}
}
public void setFirstAnalyzedDate(ZonedDateTime firstAnalyzedDate) {
this.firstAnalyzedDate = firstAnalyzedDate;
}
public void setLastAnalyzedDate(ZonedDateTime lastAnalyzedDate) {
this.lastAnalyzedDate = lastAnalyzedDate;
}
public void setMetadata(List<MetadataLabel> metadata) {
this.metadata = List.copyOf(metadata);
}
public void setStatusDescription(String statusDescription) {
this.statusDescription = statusDescription;
}
public List<CTCloudCostBean> getCost() {
return List.copyOf(cost);
}
public void setCost(List<CTCloudCostBean> cost) {
this.cost = List.copyOf(cost);
}
}

View File

@ -1,16 +1,26 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
/** *************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
************************************************************************** */
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
*
* @author gregd
* Metadata entry.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataLabel {
private final String key;

View File

@ -21,11 +21,17 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.function.Function;
/**
* Creates default ObjectMapper
@ -44,41 +50,110 @@ public class ObjectMapperUtil {
public ObjectMapper getDefaultObjectMapper() {
ObjectMapper defaultMapper = new ObjectMapper();
// defaultMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// defaultMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
defaultMapper.registerModule(new JavaTimeModule());
return defaultMapper;
}
public static class MDYDateDeserializer extends JsonDeserializer<ZonedDateTime> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("MMM dd, yyyy");
public static class ZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> {
@Override
public ZonedDateTime deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
JsonNode node = jp.getCodec().readTree(jp);
String nodeText = node.asText();
String date = jp.getText();
try {
return ZonedDateTime.parse(nodeText, FORMATTER);
LocalDateTime ldt = LocalDateTime.parse(date, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
return ZonedDateTime.of(ldt, ZoneOffset.UTC);
} catch (DateTimeParseException ex) {
return null;
}
}
}
public static class InstantEpochMillisDeserializer extends JsonDeserializer<Instant> {
// public static class MDYDateDeserializer extends JsonDeserializer<Date> {
//
// private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("MMM dd, yyyy");
//
// @Override
// public Date deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
// JsonNode node = jp.getCodec().readTree(jp);
// String nodeText = node.asText();
// try {
// return FORMATTER.parse(nodeText);
// } catch (ParseException ex) {
// return null;
// }
// }
//
// }
public static class EpochTimeDeserializer<T> extends JsonDeserializer<T> {
private final Function<Long, T> timeDeserializer;
public EpochTimeDeserializer(Function<Long, T> timeDeserializer) {
this.timeDeserializer = timeDeserializer;
}
@Override
public Instant deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
public T deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
JsonNode node = jp.getCodec().readTree(jp);
if (!node.isNumber()) {
return null;
Long timeVal = null;
if (node.isNumber()) {
timeVal = node.asLong();
} else {
String nodeText = node.asText();
try {
long millis = node.asLong();
return Instant.ofEpochMilli(millis);
timeVal = Long.parseLong(nodeText);
} catch (NumberFormatException ex) {
// do nothing if can't parse as number
}
}
if (timeVal != null) {
try {
return timeDeserializer.apply(timeVal);
} catch (DateTimeException ex) {
// do nothing if can't parse to epoch
}
}
return null;
}
}
public static class InstantEpochMillisDeserializer extends EpochTimeDeserializer<Instant> {
public InstantEpochMillisDeserializer() {
super(InstantEpochMillisDeserializer::convert);
}
private static Instant convert(Long longVal) {
try {
return Instant.ofEpochMilli(longVal);
} catch (DateTimeException ex) {
// do nothing if can't parse to epoch
return null;
}
}
}
public static class InstantEpochSecsDeserializer extends EpochTimeDeserializer<Instant> {
public InstantEpochSecsDeserializer() {
super(InstantEpochSecsDeserializer::convert);
}
private static Instant convert(Long longVal) {
try {
return Instant.ofEpochSecond(longVal);
} catch (DateTimeException ex) {
// do nothing if can't parse to epoch
return null;
}
}
}
}

View File

@ -17,12 +17,15 @@ import com.basistech.df.cybertriage.autopsy.ctoptions.subpanel.CTOptionsSubPanel
import com.basistech.df.cybertriage.autopsy.ctapi.CTCloudException;
import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
@ -34,6 +37,7 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.core.UserPreferences;
/**
* Options panel for CyberTriage options for importing a CyberTriage incident
@ -43,8 +47,13 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
private static final Logger logger = Logger.getLogger(CTMalwareScannerOptionsPanel.class.getName());
private static final SimpleDateFormat LICENSE_EXPIRES_FORMAT = new SimpleDateFormat("MMMM d, YYYY");
private static final SimpleDateFormat MALWARE_SCANS_RESET_FORMAT = new SimpleDateFormat("MMM d, YYYY' at 'h:mma");
private static final DateTimeFormatter LICENSE_EXPIRES_FORMAT = DateTimeFormatter
.ofPattern("MMMM d, YYYY")
.withZone(ZoneId.of(UserPreferences.getTimeZoneForDisplays()));
private static final DateTimeFormatter MALWARE_SCANS_RESET_FORMAT = DateTimeFormatter
.ofPattern("MMM d, YYYY' at 'h:mma")
.withZone(ZoneId.of(UserPreferences.getTimeZoneForDisplays()));
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
private final CTLicensePersistence ctPersistence = CTLicensePersistence.getInstance();
@ -171,7 +180,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
this.authTokenFetcher = new AuthTokenFetcher(licenseInfo.getDecryptedLicense().getBoostLicenseId());
this.authTokenFetcher = new AuthTokenFetcher(licenseInfo.getDecryptedLicense());
this.authTokenFetcher.execute();
}
@ -491,15 +500,15 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
"CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_desc=A general error occurred while fetching malware scans information. Please try again later.",})
private class AuthTokenFetcher extends SwingWorker<AuthTokenResponse, Void> {
private final String boostLicenseId;
private final DecryptedLicenseResponse decryptedLicense;
public AuthTokenFetcher(String boostLicenseId) {
this.boostLicenseId = boostLicenseId;
public AuthTokenFetcher(DecryptedLicenseResponse decryptedLicense) {
this.decryptedLicense = decryptedLicense;
}
@Override
protected AuthTokenResponse doInBackground() throws Exception {
return ctApiDAO.getAuthToken(boostLicenseId);
return ctApiDAO.getAuthToken(decryptedLicense);
}
@Override

View File

@ -70,7 +70,11 @@ public class BatchProcessor<T> {
private synchronized void asyncProcessBatch() throws InterruptedException {
if (!batchingQueue.isEmpty()) {
// wait for previous processing to finish
synchronized (lastProcessingFuture) {
if (!lastProcessingFuture.isDone()) {
lastProcessingFuture.wait(millisTimeout);
}
}
// if 'andThen' doesn't run, clear the processing queue
processingQueue.clear();

View File

@ -18,6 +18,6 @@ MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Time
# {0} - remainingLookups
MalwareScanIngestModule_ShareProcessing_lowLimitWarning_desc=This license only has {0} lookups remaining
MalwareScanIngestModule_ShareProcessing_lowLimitWarning_title=Hash Lookups Low
MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the CyberTriage cloud API for any possible malicious executables.
MalwareScanIngestModuleFactory_displayName=Malware Scan
MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.
MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scan
MalwareScanIngestModuleFactory_version=1.0.0

View File

@ -15,7 +15,7 @@ package com.basistech.df.cybertriage.autopsy.malwarescan;
import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResult;
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
import java.util.ArrayList;
@ -135,8 +135,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
throw new IngestModuleException("No saved license was found");
}
String licenseStr = licenseInfoOpt.get().getDecryptedLicense().getBoostLicenseId();
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseStr);
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfoOpt.get().getDecryptedLicense());
// syncronously fetch malware scans info
// determine lookups remaining
@ -161,6 +160,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
licenseInfo = licenseInfoOpt.get();
startupException = null;
noMoreHashLookups = false;
runState = RunState.STARTED_UP;
} catch (IngestModuleException ex) {
startupException = ex;
throw startupException;
@ -235,7 +235,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
try {
// get an auth token with the license
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfo.getDecryptedLicense().getBoostLicenseId());
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfo.getDecryptedLicense());
// make sure we are in bounds for the remaining scans
long remainingScans = remaining(authTokenResponse.getHashLookupLimit(), authTokenResponse.getHashLookupCount());
@ -256,14 +256,14 @@ public class MalwareScanIngestModule implements FileIngestModule {
}
// using auth token, get results
List<FileReputationResult> repResult = ctApiDAO.getReputationResults(authTokenResponse, md5Hashes);
List<CTCloudBean> repResult = ctApiDAO.getReputationResults(authTokenResponse, md5Hashes);
if (repResult != null && !repResult.isEmpty()) {
SleuthkitCase.CaseDbTransaction trans = null;
try {
trans = tskCase.beginTransaction();
for (FileReputationResult result : repResult) {
String sanitizedMd5 = sanitizedMd5(result.getMd5Hash());
for (CTCloudBean result : repResult) {
String sanitizedMd5 = sanitizedMd5(result.getMd5HashValue());
List<Long> objIds = md5ToObjId.remove(sanitizedMd5);
if (objIds == null || objIds.isEmpty()) {
continue;
@ -309,18 +309,20 @@ public class MalwareScanIngestModule implements FileIngestModule {
"MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes=YES",
"MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No=NO"
})
private void createAnalysisResult(Long objId, FileReputationResult fileReputationResult, SleuthkitCase.CaseDbTransaction trans) throws Blackboard.BlackboardException {
if (objId == null || fileReputationResult == null) {
private void createAnalysisResult(Long objId, CTCloudBean cloudBean, SleuthkitCase.CaseDbTransaction trans) throws Blackboard.BlackboardException {
if (objId == null || cloudBean == null || cloudBean.getMalwareResult() == null) {
return;
}
Score score = fileReputationResult.getScore() == null ? Score.SCORE_UNKNOWN : fileReputationResult.getScore().getTskCore();
Score score = cloudBean.getMalwareResult().getCTScore() == null
? Score.SCORE_UNKNOWN
: cloudBean.getMalwareResult().getCTScore().getTskCore();
String conclusion = score.getSignificance() == Score.Significance.NOTABLE || score.getSignificance() == Score.Significance.LIKELY_NOTABLE
? Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes()
: Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No();
String justification = fileReputationResult.getStatusDescription();
String justification = cloudBean.getMalwareResult().getStatusDescription();
tskCase.getBlackboard().newAnalysisResult(
malwareType,

View File

@ -26,8 +26,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
*/
@ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class)
@Messages({
"MalwareScanIngestModuleFactory_displayName=Malware Scan",
"MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the CyberTriage cloud API for any possible malicious executables.",
"MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scan",
"MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.",
"MalwareScanIngestModuleFactory_version=1.0.0"
})
public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {