file upload updates

This commit is contained in:
Greg DiCristofaro 2023-07-24 11:41:19 -04:00
parent b6e806f9be
commit 08a649b01c
5 changed files with 153 additions and 10 deletions

View File

@ -24,3 +24,5 @@ CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
EULADialog.cancelButton.text=Cancel EULADialog.cancelButton.text=Cancel
EULADialog.acceptButton.text=Accept EULADialog.acceptButton.text=Accept
EULADialog.title=Cyber Triage End User License Agreement EULADialog.title=Cyber Triage End User License Agreement
CTMalwareScannerOptionsPanel.fileUploadCheckbox.text=Upload executable if executable is unknown
CTMalwareScannerOptionsPanel.fileUploadPanel.border.title=File Upload

View File

@ -195,5 +195,54 @@
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </Container>
<Container class="javax.swing.JPanel" name="fileUploadPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="File Upload">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="fileUploadCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 32767]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[255, 50]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[255, 50]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fileUploadCheckboxActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -214,6 +214,8 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
countersResetLabel = new javax.swing.JLabel(); countersResetLabel = new javax.swing.JLabel();
hashLookupsRemainingLabel = new javax.swing.JLabel(); hashLookupsRemainingLabel = new javax.swing.JLabel();
fileUploadsRemainingLabel = new javax.swing.JLabel(); fileUploadsRemainingLabel = new javax.swing.JLabel();
javax.swing.JPanel fileUploadPanel = new javax.swing.JPanel();
fileUploadCheckbox = new javax.swing.JCheckBox();
setLayout(new java.awt.GridBagLayout()); setLayout(new java.awt.GridBagLayout());
@ -346,6 +348,37 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0; gridBagConstraints.weightx = 1.0;
add(malwareScansPanel, gridBagConstraints); add(malwareScansPanel, gridBagConstraints);
fileUploadPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadPanel.border.title"))); // NOI18N
fileUploadPanel.setLayout(new java.awt.GridBagLayout());
fileUploadCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(fileUploadCheckbox, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadCheckbox.text")); // NOI18N
fileUploadCheckbox.setMaximumSize(new java.awt.Dimension(32767, 32767));
fileUploadCheckbox.setMinimumSize(new java.awt.Dimension(255, 50));
fileUploadCheckbox.setPreferredSize(new java.awt.Dimension(255, 50));
fileUploadCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fileUploadCheckboxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
fileUploadPanel.add(fileUploadCheckbox, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
add(fileUploadPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@Messages({ @Messages({
@ -377,6 +410,10 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
} }
}//GEN-LAST:event_licenseInfoAddButtonActionPerformed }//GEN-LAST:event_licenseInfoAddButtonActionPerformed
private void fileUploadCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileUploadCheckboxActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_fileUploadCheckboxActionPerformed
@NbBundle.Messages({ @NbBundle.Messages({
"# {0} - userName", "# {0} - userName",
"# {1} - email", "# {1} - email",
@ -588,6 +625,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel countersResetLabel; private javax.swing.JLabel countersResetLabel;
private javax.swing.JCheckBox fileUploadCheckbox;
private javax.swing.JLabel fileUploadsRemainingLabel; private javax.swing.JLabel fileUploadsRemainingLabel;
private javax.swing.JLabel hashLookupsRemainingLabel; private javax.swing.JLabel hashLookupsRemainingLabel;
private javax.swing.JButton licenseInfoAddButton; private javax.swing.JButton licenseInfoAddButton;

View File

@ -36,8 +36,8 @@ import org.sleuthkit.datamodel.TskCoreException;
* Handles uploading of files that are unknown. * Handles uploading of files that are unknown.
*/ */
public class FileUpload { public class FileUpload {
private static final long MIN_SIZE = 1; private static final long MIN_UPLOAD_SIZE = 1;
private static final long MAX_SIZE = 1_000_000_000; private static final long MAX_UPLOAD_SIZE = 1_000_000_000;
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance(); private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
@ -49,10 +49,10 @@ public class FileUpload {
private boolean isUploadable(AbstractFile af) { private boolean isUploadable(AbstractFile af) {
long size = af.getSize(); long size = af.getSize();
return size >= MIN_SIZE && size <= MAX_SIZE; return size >= MIN_UPLOAD_SIZE && size <= MAX_UPLOAD_SIZE;
} }
public boolean tryUpload(SleuthkitCase skCase, CTCloudBean cloudBean, long objId) throws TskCoreException { private boolean upload(SleuthkitCase skCase, DecryptedLicenseResponse decrypted, CTCloudBean cloudBean, long objId) throws CTCloudException, TskCoreException {
if (!isUnknown(cloudBean)) { if (!isUnknown(cloudBean)) {
return false; return false;
} }
@ -66,10 +66,6 @@ public class FileUpload {
return false; return false;
} }
}
private boolean upload(DecryptedLicenseResponse decrypted, AbstractFile af) throws CTCloudException, TskCoreException {
// get auth token / file upload url // get auth token / file upload url
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(decrypted, true); AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(decrypted, true);
if (StringUtils.isBlank(authTokenResponse.getFileUploadUrl())) { if (StringUtils.isBlank(authTokenResponse.getFileUploadUrl())) {

View File

@ -19,10 +19,14 @@
package com.basistech.df.cybertriage.autopsy.malwarescan; package com.basistech.df.cybertriage.autopsy.malwarescan;
import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO; 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.AuthTokenResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthenticatedRequestData; 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.CTCloudBean;
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.LicenseInfo;
import com.basistech.df.cybertriage.autopsy.ctapi.json.MalwareResultBean;
import com.basistech.df.cybertriage.autopsy.ctapi.json.MetadataUploadRequest;
import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence; import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -48,8 +52,10 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
/** /**
@ -88,6 +94,9 @@ public class MalwareScanIngestModule implements FileIngestModule {
//minimum lookups left before issuing warning //minimum lookups left before issuing warning
private static final long LOW_LOOKUPS_REMAINING = 250; private static final long LOW_LOOKUPS_REMAINING = 250;
private static final long MIN_UPLOAD_SIZE = 1;
private static final long MAX_UPLOAD_SIZE = 1_000_000_000;
private static final Set<String> EXECUTABLE_MIME_TYPES = Stream.of( private static final Set<String> EXECUTABLE_MIME_TYPES = Stream.of(
"application/x-bat",//NON-NLS "application/x-bat",//NON-NLS
"application/x-dosexec",//NON-NLS "application/x-dosexec",//NON-NLS
@ -112,7 +121,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance(); private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
private RunState runState = null; private RunState runState = null;
private SleuthkitCase tskCase = null; private SleuthkitCase tskCase = null;
private FileTypeDetector fileTypeDetector = null; private FileTypeDetector fileTypeDetector = null;
private LicenseInfo licenseInfo = null; private LicenseInfo licenseInfo = null;
@ -192,6 +201,55 @@ public class MalwareScanIngestModule implements FileIngestModule {
return limit - used; return limit - used;
} }
private boolean isUnknown(CTCloudBean cloudBean) {
return cloudBean != null
&& cloudBean.getMalwareResult() != null
&& cloudBean.getMalwareResult().getStatus() == MalwareResultBean.Status.NOT_FOUND;
}
private boolean isUploadable(AbstractFile af) {
long size = af.getSize();
return size >= MIN_UPLOAD_SIZE && size <= MAX_UPLOAD_SIZE;
}
private boolean uploadFile(SleuthkitCase skCase, DecryptedLicenseResponse decrypted, CTCloudBean cloudBean, long objId) throws CTCloudException, TskCoreException {
if (!isUnknown(cloudBean)) {
return false;
}
AbstractFile af = skCase.getAbstractFileById(objId);
if (af == null) {
return false;
}
if (!isUploadable(af)) {
return false;
}
// 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;
}
@Messages({ @Messages({
"MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout", "MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout",
"MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out" "MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out"
@ -310,7 +368,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
if (!CollectionUtils.isEmpty(createdArtifacts)) { if (!CollectionUtils.isEmpty(createdArtifacts)) {
tskCase.getBlackboard().postArtifacts(createdArtifacts, Bundle.MalwareScanIngestModuleFactory_displayName(), ingestJobId); tskCase.getBlackboard().postArtifacts(createdArtifacts, Bundle.MalwareScanIngestModuleFactory_displayName(), ingestJobId);
} }
// if we only processed part of the batch, after processing, notify that we are out of scans. // if we only processed part of the batch, after processing, notify that we are out of scans.
if (exceededScanLimit) { if (exceededScanLimit) {
runState = RunState.DISABLED; runState = RunState.DISABLED;