Skip to content

Commit

Permalink
server skew, callback colors, bug fixes, and prep for future updates
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Dec 23, 2024
1 parent 2a8b5d2 commit 5efdde0
Show file tree
Hide file tree
Showing 50 changed files with 797 additions and 246 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.3.1-rc34] - 2024-12-23

### Changed

- Added the option to tag callbacks with specific colors via the UI
- Added another database field for future use to allow triggering on delayed callback checkins
- Added another database field for future use to track specific versions of payloadtypes installed

## [3.3.1-rc33] - 2024-12-17

### Changed
Expand Down
11 changes: 11 additions & 0 deletions MythicReactUI/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.69]

### Changed

- Added the ability to color individual callbacks
- Added the ability to right-click a tab and collapse all the tasks within it
- Fixed an annoyance where clicking inside a modal and dragging out would close the modal
- Updated the UI to calculate server time_skew and update streaming accordingly
- Fixed an issue with searching tasks by callback ID that wouldn't allow searching of other task options
- Added a "host" field to callback search

## [0.2.68] - 2024-12-18

### Changed
Expand Down
18 changes: 12 additions & 6 deletions MythicReactUI/src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ export const successfulLogin = (data) => {
me.server_skew = difference;
meState({
loggedIn: true,
...data,
...me,
server_skew: difference
access_token: data.access_token,
refresh_token: data.refresh_token,
user: {
...me
}
});
localStorage.setItem("user", JSON.stringify(me));
restartWebsockets();
Expand All @@ -49,13 +51,17 @@ export const successfulRefresh = (data) => {
let now = new Date();
let serverNow = new Date(data.user.current_utc_time);
const difference = (serverNow - now) / 1000;
let me = {...meState()};
let me = {...meState().user};
me.server_skew = difference;
meState({
loggedIn: true,
access_token: localStorage.getItem("access_token"),
...me
access_token: data.access_token,
refresh_token: data.refresh_token,
user: {
...me
}
});
localStorage.setItem("user", JSON.stringify(me));
}
export const FailedRefresh = () =>{
console.log("failed refresh");
Expand Down
3 changes: 2 additions & 1 deletion MythicReactUI/src/components/EventFeedNotifications.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {useEffect} from 'react';
import {gql, useSubscription} from '@apollo/client';
import {snackActions} from './utilities/Snackbar';
import {getSkewedNow} from "./utilities/Time";

//fromNow must be in ISO format for hasura/postgres stuff
//new Date().toISOString() will do it
Expand All @@ -24,7 +25,7 @@ export function EventFeedNotifications(props) {
const me = props.me;
//const fromNow = React.useRef( );
const { loading, error, data } = useSubscription(subscribe_payloads, {
variables: {fromNow: (new Date()).toISOString()},
variables: {fromNow: (getSkewedNow()).toISOString()},
fetchPolicy: "no-cache",
shouldResubscribe: true,
onError: (errorData) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function MythicDialog(props) {
style={props.style}
aria-labelledby="scroll-dialog-title"
aria-describedby="scroll-dialog-description"
onClick={dialogOnClick}
onMouseDown={dialogOnClick}
onContextMenu={dialogOnContextMenu}
>
{props.innerDialog}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import MenuItem from '@mui/material/MenuItem';
import MenuList from '@mui/material/MenuList';
import ClickAwayListener from '@mui/material/ClickAwayListener';
import Paper from '@mui/material/Paper';
import {useTheme} from '@mui/material/styles';

export function MythicTabPanel(props) {
const { children, value, index, maxHeight, tabInfo, getCallbackData, queryParams, changeSearchParam, ...other } =
Expand Down Expand Up @@ -120,7 +119,6 @@ export function MythicTabLabel(props) {
e.stopPropagation();
onCloseTab({ tabID: tabInfo.tabID, index: index });
};
const theme = useTheme();
const [openContextMenu, setOpenContextMenu] = React.useState(false);
const dropdownAnchorRef = React.useRef(null);
const handleContextClick = (event) => {
Expand Down Expand Up @@ -185,7 +183,7 @@ export function MythicTabLabel(props) {

{...a11yProps(index)}
{...other}
style={{padding: "0px 5px 0px 5px", borderRadius: "4px", margin: 0}}
style={{padding: "0px 5px 0px 5px", borderRadius: "4px", margin: 0, backgroundColor: selectedIndex === index ? tabInfo.color : ""}}
/>
);
}
Expand Down
94 changes: 69 additions & 25 deletions MythicReactUI/src/components/TopAppBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import SupervisorAccountIcon from '@mui/icons-material/SupervisorAccount';
import EditIcon from '@mui/icons-material/Edit';
import { Typography } from '@mui/material';
import SearchIcon from '@mui/icons-material/Search';
import BarChartIcon from '@mui/icons-material/BarChart';
import KeyboardIcon from '@mui/icons-material/Keyboard';
import HeadsetTwoToneIcon from '@mui/icons-material/HeadsetTwoTone';
import CodeIcon from '@mui/icons-material/Code';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
Expand All @@ -62,6 +62,9 @@ import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import {TopAppBarEventingNotifications} from "./TopAppBarEventingNotifications";
import {useQuery, gql} from '@apollo/client';
import VerifiedTwoToneIcon from '@mui/icons-material/VerifiedTwoTone';
import ConfirmationNumberIcon from '@mui/icons-material/ConfirmationNumber';
import AccountTreeIcon from '@mui/icons-material/AccountTree';
import AssignmentIcon from '@mui/icons-material/Assignment';


const PREFIX = 'TopAppBar';
Expand Down Expand Up @@ -273,7 +276,7 @@ export function TopAppBar(props) {

<ListItem button component={Link} to='/new' key={"home"} onClick={handleDrawerClose}>
<ListItemIcon ><SpaceDashboardTwoToneIcon fontSize={"large"} className="mythicElement" /></ListItemIcon>
<ListItemText primary={"Dashboard"} />
<ListItemText primary={"Dashboard / Home"} />
</ListItem>
</List>
<List
Expand Down Expand Up @@ -304,14 +307,14 @@ export function TopAppBar(props) {
</List>
</Collapse>
<ListItem button onClick={handleToggleCreate}>
<ListItemIcon><PostAddIcon /></ListItemIcon>
<ListItemIcon><PostAddIcon fontSize={"large"} /></ListItemIcon>
<ListItemText>Create</ListItemText>
{openCreate ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={openCreate} unmountOnExit>
<List component="div" disablePadding style={{border: 0}}>
<ListItem button className={classes.nested} component={Link} to='/new/createpayload' key={"createpayload"} onClick={handleDrawerClose} state={{from: 'TopAppBar'}}>
<ListItemIcon><PostAddIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemIcon><FontAwesomeIcon size={"2x"} icon={faBiohazard} /></ListItemIcon>
<ListItemText primary={"Create Payload"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/createwrapper' key={"createwrapper"} onClick={handleDrawerClose}>
Expand Down Expand Up @@ -348,40 +351,81 @@ export function TopAppBar(props) {
Operational Views
</ListSubheader>
}>
<ListItem button className={classes.listSubHeader} component={Link} to='/new/payloads' key={"payloads"} onClick={handleDrawerClose}>
<ListItemIcon><FontAwesomeIcon icon={faBiohazard} size="2x"/></ListItemIcon>
<ListItemText primary={"Payloads"} />
</ListItem>
<ListItem button onClick={handleToggleData}>
<ListItemIcon><BarChartIcon fontSize={"large"} /></ListItemIcon>
<ListItemText>Operational Data</ListItemText>
<ListItemIcon><SearchIcon fontSize={"large"} /></ListItemIcon>
<ListItemText>Search</ListItemText>
{openData ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={openData} unmountOnExit>
<List component="div" disablePadding style={{border: 0}}>
<ListItem button className={classes.nested} component={Link} to='/new/payloads' key={"payloads"} onClick={handleDrawerClose}>
<ListItemIcon><FontAwesomeIcon icon={faBiohazard} size="2x"/></ListItemIcon>
<ListItemText primary={"Payloads"} />
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=callbacks&searchField=Host&search=' onClick={handleDrawerClose}>
<ListItemIcon><PhoneCallbackIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Callbacks"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=callbacks&searchField=Host&search=' key={"search"} onClick={handleDrawerClose}>
<ListItemIcon><SearchIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Search"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/mitre' onClick={handleDrawerClose}>
<ListItemIcon><TableChartTwoToneIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"ATT&CK"} />
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=tasks&searchField=Command+and+Parameters&search=&taskStatus=' onClick={handleDrawerClose}>
<ListItemIcon><AssignmentIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Tasks"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=payloads&searchField=Filename&search=&taskStatus=&c2=All+C2&payloadtype=All+Payload+Types' onClick={handleDrawerClose}>
<ListItemIcon><FontAwesomeIcon size={"2x"} icon={faBiohazard} /></ListItemIcon>
<ListItemText primary={"Payloads"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?searchField=Filename&tab=files&location=Downloads&host=&search=' onClick={handleDrawerClose}>
<ListItemIcon><AttachmentIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Files"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?t?searchField=Account&tab=credentials&search=' onClick={handleDrawerClose}>
<ListItemIcon><VpnKeyIcon fontSize={"large"} className="mythicElement" /></ListItemIcon>
<ListItemText primary={"Credentials"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=keylogs&searchField=Host&search='onClick={handleDrawerClose}>
<ListItemIcon><KeyboardIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Keylogs"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=artifacts&searchField=Host&search=' onClick={handleDrawerClose}>
<ListItemIcon><FingerprintIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Artifacts"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/reporting' onClick={handleDrawerClose}>
<ListItemIcon><FontAwesomeIcon size={"2x"} icon={faFlagCheckered} /></ListItemIcon>
<ListItemText primary={"Reporting"} />
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=tokens&searchField=Host&search=' onClick={handleDrawerClose}>
<ListItemIcon><ConfirmationNumberIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Tokens"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/tagtypes' onClick={handleDrawerClose}>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=socks' onClick={handleDrawerClose}>
<ListItemIcon><FontAwesomeIcon size={"2x"} icon={faSocks} /></ListItemIcon>
<ListItemText primary={"Proxies"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=processes&searchField=Name&search=&host=' onClick={handleDrawerClose}>
<ListItemIcon><AccountTreeIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Processes"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/search?tab=tags&searchField=TagType&search=&host=' onClick={handleDrawerClose}>
<ListItemIcon><LocalOfferTwoToneIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Tags"} />
</ListItem>
<ListItem button className={classes.nested} component={Link} to='/new/eventing' onClick={handleDrawerClose}>
<ListItemIcon><PlayCircleFilledTwoToneIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Eventing"} />
</ListItem>
</List>

</Collapse>
<ListItem button component={Link} to='/new/callbacks' key={"callbacks"} onClick={handleDrawerClose}>
<ListItem button className={classes.listSubHeader} component={Link} to='/new/mitre' onClick={handleDrawerClose}>
<ListItemIcon><TableChartTwoToneIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"ATT&CK"} />
</ListItem>
<ListItem button className={classes.listSubHeader} component={Link} to='/new/reporting' onClick={handleDrawerClose}>
<ListItemIcon><FontAwesomeIcon size={"2x"} icon={faFlagCheckered} /></ListItemIcon>
<ListItemText primary={"Reporting"} />
</ListItem>
<ListItem button className={classes.listSubHeader} component={Link} to='/new/tagtypes' onClick={handleDrawerClose}>
<ListItemIcon><LocalOfferTwoToneIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Tags"} />
</ListItem>
<ListItem button className={classes.listSubHeader} component={Link} to='/new/eventing' onClick={handleDrawerClose}>
<ListItemIcon><PlayCircleFilledTwoToneIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Eventing"} />
</ListItem>
<ListItem className={classes.listSubHeader} button component={Link} to='/new/callbacks' key={"callbacks"} onClick={handleDrawerClose}>
<ListItemIcon><PhoneCallbackIcon fontSize={"large"} className="mythicElement"/></ListItemIcon>
<ListItemText primary={"Active Callbacks"} />
</ListItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ mutation lockCallack($callback_display_id: Int!){
}
`;
export const updateDescriptionCallbackMutation = gql`
mutation updateDescriptionCallack($callback_display_id: Int!, $description: String!){
updateCallback(input: {callback_display_id: $callback_display_id, description: $description}) {
mutation updateDescriptionCallback($callback_display_id: Int!, $description: String!, $color: String!){
updateCallback(input: {callback_display_id: $callback_display_id, description: $description, color: $color}) {
status
error
}
Expand Down
8 changes: 8 additions & 0 deletions MythicReactUI/src/components/pages/Callbacks/Callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ export function Callbacks({me}) {
}, [openTabs])
const onOpenTab = React.useRef( (tabData) => {
let found = false;
openTabRef.current = openTabRef.current.map( (tab) => {
if(tab.tabID === tabData.tabID){
return {...tabData};
}
return {...tab};
})
openTabRef.current.forEach((tab) => {
if (tab.tabID === tabData.tabID) found = true;
});
Expand All @@ -121,6 +127,8 @@ export function Callbacks({me}) {
const tabs = [...openTabRef.current, { ...tabData }];
localStorage.setItem('openTabs', JSON.stringify(tabs));
setOpenTabs(tabs);
} else {
setOpenTabs([...openTabRef.current]);
}
localStorage.setItem('clickedTab', tabData.tabID);
setClickedTabId(tabData.tabID);
Expand Down
Loading

0 comments on commit 5efdde0

Please sign in to comment.