Merge pull request #1688 from guardicore/1640-simplify-log-download

1640 simplify log download
This commit is contained in:
Mike Salvatore 2022-01-31 08:55:54 -05:00 committed by GitHub
commit 81bc579aa5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 108 additions and 70 deletions

View File

@ -8,11 +8,13 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
- credentials.json file for storing Monkey Island user login information. #1206
- The ability to download the Monkey Island logs from the Infection Map page. #1640
### Changed
- "Communicate as Backdoor User" PBA's HTTP requests to request headers only and
include a timeout. #1577
- The setup procedure for custom server_config.json files to be simpler. #1576
- "Logs" page renamed to "Telemetries". #1640
### Removed
- The VSFTPD exploiter. #1533
@ -32,6 +34,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- Hostname system info collector. #1535
- Max iterations and timeout between iterations config options. #1600
- MITRE ATT&CK configuration screen. #1532
- Island log download button from "Telemetries"(previously called "Logs") page. #1640
### Fixed
- A bug in network map page that caused delay of telemetry log loading. #1545

View File

@ -156,13 +156,23 @@ The Monkey performs queries out to the Internet on two separate occasions:
## Logging and how to find logs
### Monkey Island server logs
### Downloading logs
You can download the Monkey Island's log file directly from the UI. Click the "log" section and choose **Download Monkey Island internal logfile**, like so:
Both Monkey Agent and Monkey Island logs can be found in the Infection Map page. Click on the
machine from which you want to download logs and press the "Download log" button on the side panel.
Note that you can only download the Monkey Island log by clicking on the Monkey Island machine in
the Infection Map.
![How to download Monkey Island internal log file](/images/faq/download_log_monkey_island.png "How to download Monkey Island internal log file")
![How to download logs](/images/faq/log_download.jpg "How to download logs")
It can also be found as a local file on the Monkey Island server system in the specified
### Log locations
If the logs can't be downloaded through the UI for any reason, you can collect the log files
directly from the machine where an Agent or Monkey Island ran.
#### Monkey Island server log
The Monkey Island's log file is located in the
[data directory]({{< ref "/reference/data_directory" >}}).
The log enables you to see which requests were requested from the server and extra logs from the backend logic. The log will contain entries like these:
@ -177,7 +187,7 @@ It's also possible to change the default log level by editing `log_level` value
`log_level` can be set to `info`(default, less verbose) or `debug`(more verbose).
### Infection Monkey agent logs
#### Infection Monkey agent logs
The Infection Monkey agent log file can be found in the following paths on machines where it was executed:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

BIN
docs/static/images/faq/log_download.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View File

@ -91,7 +91,7 @@ const SideNavComponent = ({disabled,
</NavLink></li>
<li><NavLink to='/infection/telemetry'
className={getNavLinkClass()}>
Logs
Telemetries
</NavLink></li>
</ul>

View File

@ -4,8 +4,11 @@ import {faHandPointLeft} from '@fortawesome/free-solid-svg-icons/faHandPointLeft
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons/faQuestionCircle'
import Toggle from 'react-toggle';
import {OverlayTrigger, Tooltip} from 'react-bootstrap';
import download from 'downloadjs'
import AuthComponent from '../../AuthComponent';
import {
AgentLogDownloadButton,
IslandLogDownloadButton
} from '../../ui-components/LogDownloadButtons';
class PreviewPaneComponent extends AuthComponent {
@ -13,7 +16,7 @@ class PreviewPaneComponent extends AuthComponent {
return (
<OverlayTrigger placement="top"
overlay={<Tooltip id="tooltip">{text}</Tooltip>}
delay={{ show: 250, hide: 400 }}>
delay={{show: 250, hide: 400}}>
<a><FontAwesomeIcon icon={faQuestionCircle} style={{'marginRight': '0.5em'}}/></a>
</OverlayTrigger>
);
@ -94,43 +97,29 @@ class PreviewPaneComponent extends AuthComponent {
);
}
unescapeLog(st) {
return st.substr(1, st.length - 2) // remove quotation marks on beginning and end of string.
.replace(/\\n/g, '\n')
.replace(/\\r/g, '\r')
.replace(/\\t/g, '\t')
.replace(/\\b/g, '\b')
.replace(/\\f/g, '\f')
.replace(/\\"/g, '"')
.replace(/\\'/g, '\'')
.replace(/\\&/g, '&');
}
downloadLog(asset) {
this.authFetch('/api/log?id=' + asset.id)
.then(res => res.json())
.then(res => {
let timestamp = res['timestamp'];
timestamp = timestamp.substr(0, timestamp.indexOf('.'));
let filename = res['monkey_label'].split(':').join('-') + ' - ' + timestamp + '.log';
let logContent = this.unescapeLog(res['log']);
download(logContent, filename, 'text/plain');
});
}
downloadLogRow(asset) {
downloadLogsRow(asset) {
return (
<>
<tr>
<th>
Download Log
Download Monkey Agent Log
</th>
<td>
<a type='button'
className={asset.has_log ? 'btn btn-primary' : 'btn btn-primary disabled'}
onClick={() => this.downloadLog(asset)}>Download</a>
<AgentLogDownloadButton url={'/api/log?id=' + asset.id}
variant={asset.has_log ? undefined : 'disabled'}/>
</td>
</tr>
{(asset['group'].includes('island')) &&
<tr>
<th>
Download Island Server Log
</th>
<td>
<IslandLogDownloadButton url={'/api/log/island/download'} />
</td>
</tr>
}
</>
);
}
@ -194,7 +183,7 @@ class PreviewPaneComponent extends AuthComponent {
{this.servicesRow(asset)}
{this.accessibleRow(asset)}
{this.forceKillRow(asset)}
{this.downloadLogRow(asset)}
{this.downloadLogsRow(asset)}
</tbody>
</table>
{this.exploitsTimeline(asset)}

View File

@ -1,12 +1,9 @@
import React from 'react';
import {Button, Col} from 'react-bootstrap';
import {Col} from 'react-bootstrap';
import AuthService from '../../services/AuthService';
import download from 'downloadjs';
import TelemetryLogTable from '../ui-components/TelemetryLogTable'
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import '../../styles/pages/TelemetryPage.scss';
import {faDownload} from '@fortawesome/free-solid-svg-icons/faDownload';
class TelemetryPageComponent extends React.Component {
@ -19,35 +16,15 @@ class TelemetryPageComponent extends React.Component {
};
}
downloadIslandLog = () => {
this.authFetch('/api/log/island/download')
.then(res => res.json())
.then(res => {
let filename = 'Island_log';
let logContent = (res['log_file']);
download(logContent, filename, 'text/plain');
});
};
render() {
return (
<Col sm={{offset: 3, span: 9}} md={{offset: 3, span: 9}}
lg={{offset: 3, span: 9}} xl={{offset: 2, span: 7}}
className={'main'}>
<div>
<h1 className="page-title">Logs</h1>
<h1 className="page-title">Agent telemetries</h1>
<TelemetryLogTable/>
</div>
<div>
<h1 className="page-title"> Monkey Island Logs </h1>
<div className="text-center" style={{marginBottom: '20px'}}>
<p style={{'marginBottom': '2em', 'fontSize': '1.2em'}}> Download Monkey Island internal log file </p>
<Button bsSize="large" onClick={() => {
this.downloadIslandLog();
}}>
<FontAwesomeIcon icon={faDownload}/> Download </Button>
</div>
</div>
</Col>
);
}

View File

@ -0,0 +1,59 @@
import React from 'react';
import AuthComponent from '../AuthComponent';
import download from 'downloadjs';
import {Button} from 'react-bootstrap';
const authComponent = new AuthComponent({})
type Props = { url: string, filename: string, variant?: string}
export const AgentLogDownloadButton = ({ url, variant = 'primary'}: Props) => {
function unescapeLog(st) {
return st.substr(1, st.length - 2) // remove quotation marks on beginning and end of string.
.replace(/\\n/g, '\n')
.replace(/\\r/g, '\r')
.replace(/\\t/g, '\t')
.replace(/\\b/g, '\b')
.replace(/\\f/g, '\f')
.replace(/\\"/g, '"')
.replace(/\\'/g, '\'')
.replace(/\\&/g, '&');
}
function downloadAgentLog() {
authComponent.authFetch(url)
.then(res => res.json())
.then(res => {
let timestamp = res['timestamp'];
timestamp = timestamp.substr(0, timestamp.indexOf('.'));
let filename = res['monkey_label'].split(':').join('-') + ' - ' + timestamp + '.log';
let logContent = unescapeLog(res['log']);
download(logContent, filename, 'text/plain');
});
}
return (<Button variant={variant}
onClick={downloadAgentLog}>
Download Log
</Button>);
}
export const IslandLogDownloadButton = ({ url, variant = 'primary'}: Props) => {
function downloadIslandLog() {
authComponent.authFetch(url)
.then(res => res.json())
.then(res => {
let filename = 'Island_log';
let logContent = (res['log_file']);
download(logContent, filename, 'text/plain');
});
}
return (<Button variant={variant}
onClick={downloadIslandLog}>
Download Log
</Button>);
}