file upload

This commit is contained in:
Greg DiCristofaro 2023-07-24 09:34:15 -04:00
parent b16cbe6c1d
commit 8809569567
4 changed files with 249 additions and 16 deletions

View File

@ -21,17 +21,13 @@ package com.basistech.df.cybertriage.autopsy.ctapi;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -41,13 +37,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.logging.Level;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
@ -64,7 +54,9 @@ import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
@ -175,10 +167,14 @@ public class CTCloudHttpClient {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
LOGGER.log(Level.INFO, "Response Received. - Status OK");
// Parse Response
HttpEntity entity = response.getEntity();
String entityStr = EntityUtils.toString(entity);
O respObj = mapper.readValue(entityStr, classType);
return respObj;
if (classType != null) {
HttpEntity entity = response.getEntity();
String entityStr = EntityUtils.toString(entity);
O respObj = mapper.readValue(entityStr, classType);
return respObj;
} else {
return null;
}
} else {
LOGGER.log(Level.WARNING, "Response Received. - Status Error {}", response.getStatusLine());
handleNonOKResponse(response, "");
@ -198,6 +194,40 @@ public class CTCloudHttpClient {
return null;
}
public void doFileUploadPost(String urlPath, String fileName, InputStream fileIs) throws CTCloudException {
try (CloseableHttpClient httpclient = createConnection(getProxySettings(), sslContext)) {
HttpPost post = new HttpPost(urlPath);
configureRequestTimeout(post);
post.addHeader("Connection", "keep-alive");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody(
"file",
fileIs,
ContentType.APPLICATION_OCTET_STREAM,
fileName
);
HttpEntity multipart = builder.build();
post.setEntity(multipart);
try (CloseableHttpResponse response = httpclient.execute(post)) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_NO_CONTENT) {
LOGGER.log(Level.INFO, "Response Received. - Status OK");
} else {
LOGGER.log(Level.WARNING, MessageFormat.format("Response Received. - Status Error {0}", response.getStatusLine()));
handleNonOKResponse(response, fileName);
}
}
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to Reversing Labs for file content upload ", ex);
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
}
}
/**
* A generic way to handle the HTTP response - when the response code is NOT

View File

@ -27,7 +27,9 @@ 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.LicenseRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.MetadataUploadRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -44,6 +46,8 @@ public class CTApiDAO {
private static final String LICENSE_REQUEST_PATH = "/_ah/api/license/v1/activate";
private static final String AUTH_TOKEN_REQUEST_PATH = "/_ah/api/auth/v2/generate_token";
private static final String CTCLOUD_SERVER_HASH_PATH = "/_ah/api/reputation/v1/query/file/hash/md5?query_types=CORRELATION,MALWARE";
private static final String CTCLOUD_UPLOAD_FILE_METADATA_PATH = "/_ah/api/reputation/v1/upload/meta";
private static final String AUTOPSY_PRODUCT = "AUTOPSY";
private static final CTApiDAO instance = new CTApiDAO();
@ -72,15 +76,27 @@ public class CTApiDAO {
}
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted) throws CTCloudException {
return getAuthToken(decrypted, false);
}
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted, boolean fileUpload) throws CTCloudException {
AuthTokenRequest authTokenRequest = new AuthTokenRequest()
.setAutopsyVersion(getAppVersion())
.setRequestFileUpload(false)
.setRequestFileUpload(fileUpload)
.setBoostLicenseId(decrypted.getBoostLicenseId())
.setHostId(decrypted.getLicenseHostId());
return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
}
public void uploadFile(String url, String fileName, InputStream fileIs) throws CTCloudException {
httpClient.doFileUploadPost(url, fileName, fileIs);
}
public void uploadMeta(AuthenticatedRequestData authenticatedRequestData, MetadataUploadRequest metaRequest) throws CTCloudException {
httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, getAuthParams(authenticatedRequestData), metaRequest, null);
}
private static Map<String, String> getAuthParams(AuthenticatedRequestData authenticatedRequestData) {
return new HashMap<String, String>() {
{

View File

@ -0,0 +1,109 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonProperty;
public class MetadataUploadRequest {
@JsonProperty("file_upload_url")
private String fileUploadUrl;
@JsonProperty("sha1")
private String sha1;
@JsonProperty("sha256")
private String sha256;
@JsonProperty("md5")
private String md5;
@JsonProperty("filePath")
private String filePath;
@JsonProperty("fileSize")
private long fileSizeBytes;
@JsonProperty("createdDate")
private long createdDate;
public String getFileUploadUrl() {
return fileUploadUrl;
}
public MetadataUploadRequest setFileUploadUrl(String fileUploadUrl) {
this.fileUploadUrl = fileUploadUrl;
return this;
}
public String getSha1() {
return sha1;
}
public MetadataUploadRequest setSha1(String sha1) {
this.sha1 = sha1;
return this;
}
public String getSha256() {
return sha256;
}
public MetadataUploadRequest setSha256(String sha256) {
this.sha256 = sha256;
return this;
}
public String getMd5() {
return md5;
}
public MetadataUploadRequest setMd5(String md5) {
this.md5 = md5;
return this;
}
public String getFilePath() {
return filePath;
}
public MetadataUploadRequest setFilePath(String filePath) {
this.filePath = filePath;
return this;
}
public long getFileSizeBytes() {
return fileSizeBytes;
}
public MetadataUploadRequest setFileSizeBytes(long fileSizeBytes) {
this.fileSizeBytes = fileSizeBytes;
return this;
}
public long getCreatedDate() {
return createdDate;
}
public MetadataUploadRequest setCreatedDate(long createdDate) {
this.createdDate = createdDate;
return this;
}
}

View File

@ -0,0 +1,78 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.basistech.df.cybertriage.autopsy.malwarescan;
import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
import com.basistech.df.cybertriage.autopsy.ctapi.CTCloudException;
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.DecryptedLicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.MetadataUploadRequest;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Handles uploading of files that are unknown.
*/
public class FileUpload {
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
private boolean isUnknown(CTCloudBean cloudBean) {
}
private boolean isUploadable(AbstractFile af) {
}
public boolean tryUpload(SleuthkitCase skCase, CTCloudBean cloudBean, long objId) {
}
private boolean upload(DecryptedLicenseResponse decrypted, AbstractFile af) throws CTCloudException, TskCoreException {
// get auth token / file upload url
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(decrypted, true);
if (StringUtils.isBlank(authTokenResponse.getFileUploadUrl())) {
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR);
}
// upload bytes
ReadContentInputStream fileInputStream = new ReadContentInputStream(af);
ctApiDAO.uploadFile(authTokenResponse.getFileUploadUrl(), af.getName(), fileInputStream);
// upload metadata
MetadataUploadRequest metaRequest = new MetadataUploadRequest()
.setCreatedDate(af.getCrtime())
.setFilePath(af.getUniquePath())
.setFileSizeBytes(af.getSize())
.setFileUploadUrl(authTokenResponse.getFileUploadUrl())
.setMd5(af.getMd5Hash())
.setSha1(af.getSha1Hash())
.setSha256(af.getSha256Hash());
ctApiDAO.uploadMeta(new AuthenticatedRequestData(decrypted, authTokenResponse), metaRequest);
return true;
}
}