Skip to content

Commit

Permalink
Adding VB Card
Browse files Browse the repository at this point in the history
  • Loading branch information
phutelmyer committed Jan 9, 2024
1 parent 8246dda commit 2b68b6c
Show file tree
Hide file tree
Showing 6 changed files with 550 additions and 26 deletions.
9 changes: 5 additions & 4 deletions ui/src/components/FileComponents/FileTypeOverviewCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const FileTypeOverviewCard = ({ data, onFileTypeSelect }) => {
const [selectedFileType, setSelectedFileType] = useState(null);
const [showMoreFileTypes, setShowMoreFileTypes] = useState(false);
const MAX_ITEMS_VISIBLE = 10;


// Handler for selecting or deselecting a file type
const selectFileType = (mimeType) => {
Expand All @@ -22,12 +23,12 @@ const FileTypeOverviewCard = ({ data, onFileTypeSelect }) => {

// Iterate over the strelka_response to populate mimeTypeDetails
data.strelka_response.forEach((response) => {
const mimeType = response.file.flavors.mime[0];
const mimeType = (response.file?.flavors?.yara && response.file.flavors?.yara[0]) || response.file.flavors.mime[0];
if (mimeTypeDetails[mimeType]) {
mimeTypeDetails[mimeType].count++;
mimeTypeDetails[mimeType].files.push(response.file.name); // Add filename to array
mimeTypeDetails[mimeType].files.push(response.file.name || response.file.scan?.hash.md5); // Add filename to array
} else {
mimeTypeDetails[mimeType] = { count: 1, files: [response.file.name] }; // Initialize with first filename
mimeTypeDetails[mimeType] = { count: 1, files: [response.file.name || response.scan?.hash.md5] }; // Initialize with first filename
}
});

Expand Down Expand Up @@ -122,4 +123,4 @@ const FileTypeOverviewCard = ({ data, onFileTypeSelect }) => {
);
};

export default FileTypeOverviewCard;
export default FileTypeOverviewCard;
77 changes: 77 additions & 0 deletions ui/src/components/FileComponents/VbOverviewCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState } from "react";
import { Input, Checkbox, Typography, Row, Col } from "antd";
import "../../styles/ExiftoolOverviewCard.css"

const { Text } = Typography;

const VbOverviewCard = ({ data }) => {
const [filter, setFilter] = useState("");
const [wrapText, setWrapText] = useState(false);
const [trimText, setTrimText] = useState(true);

// Function to process VB script data for display
const processVbData = (key) => {
return data.scan.vb[key]
.filter((value) => {
const searchTerm = filter.toLowerCase();
return !filter || value.toLowerCase().includes(searchTerm);
})
.map((value, index) => {
let processedValue = value;
if (trimText && typeof processedValue === "string") {
processedValue = processedValue.trim();
}
if (!wrapText) {
processedValue = typeof processedValue === "string" ? processedValue.replace(/\s+/g, " ") : processedValue;
}
return { line: index + 1, value: processedValue };
});
};

const renderVbSection = (title, key) => {
const vbData = processVbData(key);
return (
<div
className="exif-data-list"
style={{ maxHeight: "400px", overflow: "auto" }}
>
<Text strong style={{ fontSize: "14px", marginBottom: "10px" }}>{title}</Text>
{vbData.map(({ line, label, value }) => (
<Row key={line} className="exif-data-row">
<Col span={1} className="line-number">
<div style={{ fontSize: "12px" }}>{line}</div>
</Col>
<Col span={22} className="exif-data-value">
<Text code copyable style={{ fontSize: "12px" }}>
{typeof value === "string" ? value : JSON.stringify(value)}
</Text>
</Col>
</Row>
))}
</div>
);
};

return (
<div className="vb-overview">
<Row gutter={[16, 16]}>
<Col span={18}>
<Input placeholder="Filter" onChange={(e) => setFilter(e.target.value)} style={{ width: "100%" }} />
</Col>
<Col span={6}>
<Checkbox checked={wrapText} onChange={(e) => setWrapText(e.target.checked)}>Wrap</Checkbox>
<Checkbox checked={trimText} onChange={(e) => setTrimText(e.target.checked)}>Trim</Checkbox>
</Col>
</Row>

{renderVbSection("Tokens", "tokens")}
{renderVbSection("Comments", "comments")}
{renderVbSection("Functions", "functions")}
{renderVbSection("Names", "names")}
{renderVbSection("Operators", "operators")}
{renderVbSection("Strings", "strings")}
</div>
);
};

export default VbOverviewCard;
6 changes: 3 additions & 3 deletions ui/src/components/FileComponents/YaraTypeOverviewCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ const YaraTypeOverviewCard = ({ data, onFileYaraSelect }) => {
yaraMatches.forEach((match) => {
if (yaraCounts[match]) {
yaraCounts[match].count++;
yaraCounts[match].files.push(response.file.name);
yaraCounts[match].files.push(response.file.name || response.scan.hash.md5);
} else {
yaraCounts[match] = { count: 1, files: [response.file.name] };
yaraCounts[match] = { count: 1, files: [response.file.name || response.scan.hash.md5] };
}
});
});
Expand Down Expand Up @@ -199,4 +199,4 @@ const YaraTypeOverviewCard = ({ data, onFileYaraSelect }) => {
);
};

export default YaraTypeOverviewCard;
export default YaraTypeOverviewCard;
6 changes: 3 additions & 3 deletions ui/src/components/SubmissionTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,11 @@ const SubmissionTable = () => {
) {
// Use the second record's MIME type if it exists
if (full.strelka_response.length > 1) {
mimeType = full.strelka_response[1].file.flavors.mime[0];
mimeType = full.strelka_response[1].file.flavors.yara[0] || full.strelka_response[1].file.flavors.mime[0];
}
} else {
// Use the first record's MIME type
mimeType = full.strelka_response[0].file.flavors.mime[0];
mimeType = full.strelka_response[0].file.flavors.yara[0] || full.strelka_response[0].file.flavors.mime[0];
}
}

Expand Down Expand Up @@ -483,4 +483,4 @@ const SubmissionTable = () => {
);
};

export default SubmissionTable;
export default SubmissionTable;
60 changes: 46 additions & 14 deletions ui/src/pages/SubmissionView.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import AuthCtx from "../contexts/auth";
import { fetchWithTimeout } from "../util";

import "../styles/IconContainer.css";
import VbOverviewCard from "../components/FileComponents/VbOverviewCard";

const { Text } = Typography;

Expand Down Expand Up @@ -78,12 +79,20 @@ const SubmissionsPage = (props) => {
}
}, [fileNameFilter, fileTypeFilter, fileYaraFilter]);


const getFileIcon = () => {
const mappingEntry = getIconConfig(
"strelka",
selectedNodeData["file"]["flavors"]["mime"][0].toLowerCase()
);
let flavorKey;
if (
selectedNodeData["file"]["flavors"]["yara"] &&
selectedNodeData["file"]["flavors"]["yara"].length > 0
) {
// Use YARA flavor if available
flavorKey = selectedNodeData["file"]["flavors"]["yara"][0].toLowerCase();
} else {
// Use MIME flavor if YARA is not available
flavorKey = selectedNodeData["file"]["flavors"]["mime"][0].toLowerCase();
}

const mappingEntry = getIconConfig("strelka", flavorKey);
const IconComponent = mappingEntry?.icon;
const bgColor = mappingEntry?.color || "defaultBackgroundColor";

Expand All @@ -105,12 +114,10 @@ const SubmissionsPage = (props) => {
if (virustotalPositives === -1) {
disposition = "Not Found on VirusTotal";
color = "default";
}
else if (virustotalPositives === -3) {
} else if (virustotalPositives === -3) {
disposition = "Exceeded VirusTotal Limit";
color = "warning";
}
else if (virustotalPositives === -2) {
color = "warning";
} else if (virustotalPositives === -2) {
disposition = "VirusTotal Not Enabled";
color = "default";
} else if (virustotalPositives > 5) {
Expand Down Expand Up @@ -266,7 +273,7 @@ const SubmissionsPage = (props) => {
defaultActiveKey={[1]}
style={{ width: "100%", marginBottom: "10px" }}
>
<Collapse.Panel header={<Text>File Mimetypes</Text>} key="1">
<Collapse.Panel header={<Text>File Types</Text>} key="1">
<FileTypeOverviewCard
data={data}
onFileTypeSelect={handleFileTypeSelect}
Expand Down Expand Up @@ -323,9 +330,13 @@ const SubmissionsPage = (props) => {
{getFileIcon()}
<div style={{ marginLeft: "8px" }}>
{" "}
<Text strong>{selectedNodeData.file.name}</Text>
<Text strong>
{selectedNodeData.file.name || "No Filename"}
</Text>
<div style={{ fontSize: "smaller", color: "#888" }}>
{selectedNodeData.file.flavors.mime[0]}
{(selectedNodeData.file.flavors?.yara &&
selectedNodeData.file.flavors.yara[0]) ||
selectedNodeData.file.flavors.mime[0]}
</div>
</div>
</div>
Expand Down Expand Up @@ -478,6 +489,27 @@ const SubmissionsPage = (props) => {
</Collapse.Panel>
</Collapse>
)}
{selectedNodeData && selectedNodeData.scan.vb && (
<Collapse
defaultActiveKey={[]}
style={{ width: "100%", marginBottom: "10px" }}
>
<Collapse.Panel
header={
<div style={{ marginLeft: "8px" }}>
<Text strong>Visual Basic</Text>
<div style={{ fontSize: "smaller", color: "#888" }}>
Script Length:{" "}
{selectedNodeData.scan.vb?.script_length_bytes} bytes
</div>
</div>
}
key="1"
>
<VbOverviewCard data={selectedNodeData} />
</Collapse.Panel>
</Collapse>
)}
{selectedNodeData && selectedNodeData.scan.exiftool && (
<Collapse
defaultActiveKey={[]}
Expand Down Expand Up @@ -593,4 +625,4 @@ const SubmissionsPage = (props) => {
);
};

export default SubmissionsPage;
export default SubmissionsPage;
Loading

0 comments on commit 2b68b6c

Please sign in to comment.