This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
cyber-narrator-cn-ui/src/views/detections/overview/DetectionSecurityEventOverview.vue

511 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="detection-detail-overview">
<div class="overview__left">
<div class="overview__title">{{ $t('overall.remark') }}</div>
<div class="overview__row">
<div class="row__content1" v-if="detection.eventType === 'Command and Control' && detection.isBuiltin == 1">
<span class="row__content--link">{{detection.victimIp}}</span>&nbsp;&nbsp;communicated with&nbsp;<span class="row__content--link">{{detection.offenderIp}}</span>&nbsp;&nbsp;that was associated with the indicator of {{detection.eventName}} activity, {{$_.get(detection, 'eventInfoObj.ioc_value', '') || ''}}.
</div>
<div class="row__content1" v-else-if="detection.eventType === 'Anonymity' && detection.isBuiltin == 1">
<span class="row__content--link">{{detection.victimIp}}</span>&nbsp;&nbsp;communicated with&nbsp;<span class="row__content--link">{{detection.offenderIp}}</span>&nbsp;&nbsp;that was associated with the indicator of {{detection.eventName}}.
</div>
<div class="row__content1" v-else>
{{basicInfo.ruleDescription || '-'}}
</div>
</div>
<div class="overview__title">Fields</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.list.startTime') }}</div>
<div class="row__content">
<i class="cn-icon cn-icon-time2 row__content__icon"></i>
{{ detection.startTime ? dateFormatByAppearance(detection.startTime) : '-' }}
</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.victimIp') }}</div>
<div class="row__content">{{ detection.victimIp || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.victimLocation') }}</div>
<div class="row__content">
<div v-if="$_.get(basicInfo, 'victimInfo.location.country')">
<img v-if="basicInfo.victimInfo.location.country===countryNameIdMapping.Unknown || !countryNameIdMapping[basicInfo.victimInfo.location.country]" src="../../../../public/images/flag/Unknown.svg" class="filter-country-flag">
<img v-else :src="require(`../../../../public/images/flag/${countryNameIdMapping[basicInfo.victimInfo.location.country]}.png`)" class="filter-country-flag" >
</div>
{{ locationRegion(basicInfo.victimInfo) }}
</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.victimAsn') }}</div>
<div class="row__content">{{ $_.get(basicInfo, 'victimInfo.asn.asn', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.offenderIp') }}</div>
<div class="row__content">{{ detection.offenderIp || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.offenderLocation') }}</div>
<div class="row__content">
<div v-if="$_.get(basicInfo, 'offenderInfo.location.country')">
<img v-if="basicInfo.offenderInfo.location.country===countryNameIdMapping.Unknown || !countryNameIdMapping[basicInfo.offenderInfo.location.country]" src="../../../../public/images/flag/Unknown.svg" class="filter-country-flag">
<img v-else :src="require(`../../../../public/images/flag/${countryNameIdMapping[basicInfo.offenderInfo.location.country]}.png`)" class="filter-country-flag" >
</div>
{{ locationRegion(basicInfo.offenderInfo) }}
</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.offenderAsn') }}</div>
<div class="row__content">{{ $_.get(basicInfo, 'offenderInfo.asn.asn', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('overall.domain') }}</div>
<div class="row__content">{{ detection.domain || '-' }}</div>
</div>
<template v-if="detection.domain">
<div class="overview__row">
<div class="row__label">{{ $t('entities.domainCategory') }}</div>
<div class="row__content">{{ $_.get(basicInfo, 'domainInfo.category.categoryName', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('entities.domainDetail.categoryGroup') }}</div>
<div class="row__content">{{ $_.get(basicInfo, 'domainInfo.category.categoryGroup', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('entities.reputationLevel') }}</div>
<div class="row__content" v-if="$_.get(basicInfo, 'domainInfo.category.reputationLevel')">
<div
class="row__tag row__tag__level"
:style="`background-color:${eventSeverityColor[basicInfo.domainInfo.category.reputationLevel]}`">
{{ basicInfo.domainInfo.category.reputationLevel }}
</div>
</div>
<div class="row__content" v-else>-</div>
</div>
</template>
<template v-if="detection.app">
<div class="overview__row">
<div class="row__label">APP</div>
<div class="row__content">{{ $_.get(basicInfo, 'appInfo.category.appName', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">APP {{ $t('entities.category') }}</div>
<div class="row__content">{{ $_.get(basicInfo, 'appInfo.category.appCategory', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">APP {{ $t('entities.subcategory') }}</div>
<div class="row__content">{{ $_.get(basicInfo, 'appInfo.category.appSubcategory', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('overall.appRisk') }}</div>
<div class="row__content" v-if="$_.get(basicInfo, 'appInfo.category.appRisk')">
<div
class="row__tag row__tag__level"
:style="`background-color:${riskLevelColor[basicInfo.appInfo.category.appRisk]}`">
{{ appRisk(basicInfo.appInfo.category.appRisk) || '-' }}
</div>
</div>
<div class="row__content" v-else>-</div>
</div>
</template>
<template v-if="detection.malware">
<div class="overview__row">
<div class="row__label">{{ $t('detections.malware') }}</div>
<div class="row__content">{{ $_.get(detection, 'malware.malwareName', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.malwareAlias') }}</div>
<div class="row__content">{{ $_.get(detection, 'malware.malwareAlias', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.malwareDescription') }}</div>
<div class="row__content">{{ $_.get(detection, 'malware.mitreAttackDescription', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.malwarePlatforms') }}</div>
<div class="row__content" v-if="$_.get(detection, 'malware.mitreAttackPlatforms')">
<svg class="icon item-popover-up row__content__svg" aria-hidden="true">
<use xlink:href="#cn-icon-windows"></use>
</svg>
{{ basicInfo.malwareInfo.mitreAttackPlatforms }}
</div>
<div class="row__content" v-else>-</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.malwareTechniques') }}</div>
<div class="row__content">{{ $_.get(detection, 'malware.mitreAttackTechniques', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.malwareGroups') }}</div>
<div class="row__content">{{ $_.get(detection, 'malware.mitreAttackGroups', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detections.reference') }}</div>
<div class="row__content row__content--link" v-if="$_.get(detection, 'malware.reference')">
{{ basicInfo.malwareInfo.reference }}
</div>
<div class="row__content">-</div>
</div>
</template>
<template v-else-if="detection.darkweb">
<div class="overview__row">
<div class="row__label">{{ $t('detection.nodeTypeLower') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.nodeType', '-') || '-' }}</div>
</div>
<template v-if="$_.get(detection.darkweb, 'nodeType', '') === 'tor'">
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.torFingerprint') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.torFingerprint', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.torFlags') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.torFlags', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.torVersion') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.torVersion', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">Tor ORPort</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.torOrPort', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">Tor DirPort</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.torDirPort', '-') || '-' }}</div>
</div>
</template>
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'i2p'">
<div class="overview__row">
<div class="row__label">I2P Hash</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.i2pHash', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.i2pVersion') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.i2pVersion', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.i2pBandwidth') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.i2pBandwidth', '-') || '-' }}</div>
</div>
</template>
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'mtproxy'">
<div class="overview__row">
<div class="row__label">MTProxy Secret</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.mtproxySecret', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.mtproxyPort') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.mtproxyPort', '-') || '-' }}</div>
</div>
</template>
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'obfs4'">
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.obfs4Fingerprint') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4Fingerprint', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.obfs4Cert') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4Cert', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.obfs4IatMode') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4IatMode', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.obfs4Port') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4Port', '-') || '-' }}</div>
</div>
</template>
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'snowflake'">
<div class="overview__row">
<div class="row__label">{{ $t('detection.tor.snowflakePort') }}</div>
<div class="row__content">{{ $_.get(detection, 'darkweb.snowflakePort', '-') || '-' }}</div>
</div>
</template>
</template>
<template v-else>
<div class="overview__row">
<div class="row__label">{{ $t('detection.libraryId') }}</div>
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.knowledge_id', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.libraryName') }}</div>
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.name', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.iocType') }}</div>
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.ioc_type', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.iocValue') }}</div>
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.ioc_value', '-') || '-' }}</div>
</div>
</template>
</div>
<div class="overview__right">
<div class="overview__title">{{ $t('detections.goToVictim') }}</div>
<div class="overview__row">
<div class="row__content">
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('ip', detection.victimIp)">{{ detection.victimIp }}</span>
</div>
</div>
<div class="overview__title">{{ $t('detections.goToOffender') }}</div>
<div class="overview__row">
<div class="row__content">
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('ip', detection.offenderIp)"
>{{ detection.offenderIp }}</span
>&nbsp;&nbsp;
<span
class="row__content--link"
@click="goDetail('domain', detection.domain)"
>{{ detection.domain }}</span
>
</div>
</div>
<!-- <div class="overview__title">{{ $t('detections.goToHunt') }}</div>-->
<!-- <div class="overview__row">-->
<!-- <div class="row__content row__content&#45;&#45;link">-->
<!-- {{ $t('detections.viewAllRelated') }}-->
<!-- </div>-->
<!-- </div>-->
<div class="overview__title">
{{ $t('detections.relatedDetections') }}
</div>
<div class="overview__row-timeline">
<div class="row-timeline" v-for="event in events" :key="event">
<div
class="row-timeline__time-info"
:style="
event.startTime === basicInfo.startTime
? 'color: #333;font-weight: bold;'
: ''
"
>
{{ formatT0(event) }}
</div>
<div class="row-timeline__line">
<div
class="line-point-larger"
v-if="event.startTime === basicInfo.startTime"
>
<div class="line-point"></div>
</div>
<div v-else class="line-point"></div>
</div>
<div class="row-timeline__card">
<div>
<div class="timeline__severity timeline__severity--high">
<i
class="cn-icon cn-icon-alert-level"
:style="`color:${eventSeverityColor[event.severity]}`"
></i>
<span>{{ event.severity }}</span>
</div>
<div class="timeline__security-type">{{ event.eventType }}</div>
<div class="timeline__start-time">{{ dateFormatByAppearance(parseInt(event.startTime)) }}</div>
</div>
</div>
<div class="row-timeline__foot">
<div
class="detection-ip"
:class="{
'detection-ip__current':
[detection.offenderIp, detection.victimIp].indexOf(
event.offenderIp,
) > -1,
}"
>
<i class="cn-icon cn-icon-attacker"></i>
<span>{{ event.offenderIp }}</span>
</div>
<div
class="detection-ip"
:class="{
'detection-ip__current':
[detection.offenderIp, detection.victimIp].indexOf(
event.victimIp,
) > -1,
}"
>
<i class="cn-icon cn-icon-attacked"></i>
<span>{{ event.victimIp }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { api } from '@/utils/api'
import { getMillisecond, dateFormatByAppearance } from '@/utils/date-util'
import { eventSeverityColor, unitTypes, countryNameIdMapping, riskLevelMapping, riskLevelColor } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import _ from 'lodash'
export default {
name: 'DetectionOverview',
props: {
detection: Object
},
data () {
return {
eventSeverityColor,
riskLevelColor,
basicInfo: {},
events: [],
reference: 'https://attack.mitre.org',
countryNameIdMapping
}
},
computed: {
formatT0 () {
const vm = this
return function (event) {
const diffSeconds = parseInt(event.diffSeconds)
if (diffSeconds === 0) {
return 'T0'
}
const eventStartTime = parseInt(event.startTime)
const entityStartTime = vm.detection.startTime
if (_.isNumber(diffSeconds) && _.isNumber(eventStartTime) && _.isNumber(entityStartTime)) {
const suffix = unitConvert(diffSeconds, unitTypes.time, 's', null, 0).join('')
if (eventStartTime > entityStartTime) {
return `T0+${suffix}`
} else if (eventStartTime < entityStartTime) {
return `T0-${suffix}`
}
}
return ''
}
},
appRisk () {
return function (level) {
const m = riskLevelMapping.find(mapping => {
return mapping.value == level
})
return (m && m.name) || level
}
},
locationRegion (info) {
return function (info) {
if (!info || !info.location) {
return '-'
}
let result = ''
if (info.location.country) {
result += `${info.location.country},`
}
if (info.location.province) {
result += `${info.location.province},`
}
if (info.location.city) {
result += `${info.location.city},`
}
result = result.substr(0, result.length - 1)
if (!result) {
result = '-'
}
return result
}
}
},
methods: {
getMillisecond,
dateFormatByAppearance,
/** 初始化实体详情 */
initEntityDetail () {
// 为完整填充IP信息攻击者ip、受害者ip都进行调用
// 根据detection的eventInfo对象的ioc_type进行判断若为domainmalware信息从domain详情中获取并填充domain信息
// 若ioc_type为ip则调用ip接口填充malware信息
// 最后调用app填充app信息。经上获取完整实体详情则最少需要调用4次接口
if (this.detection.offenderIp) {
axios.get(`${api.detection.securityEvent.ipDetail}?resource=${this.detection.offenderIp}`).then(res => {
if (res.status === 200) {
this.basicInfo.offenderInfo = res.data.data
}
})
}
if (this.detection.victimIp) {
axios.get(`${api.detection.securityEvent.ipDetail}?resource=${this.detection.victimIp}`).then(res => {
if (res.status === 200) {
this.basicInfo.victimInfo = res.data.data
}
})
}
if (this.detection.domain) {
axios.get(`${api.detection.securityEvent.domainDetail}?resource=${this.detection.domain}`).then(res => {
if (res.status === 200) {
this.basicInfo.domainInfo = res.data.data
}
})
}
if (this.detection.app) {
axios.get(`${api.detection.securityEvent.appDetail}?resource=${this.detection.app}`).then(res => {
if (res.status === 200) {
this.basicInfo.appInfo = res.data.data
}
})
}
if (this.detection.ruleId) {
axios.get(`${api.detection.detail}/${this.detection.ruleId}`).then(res => {
if (res.status === 200) {
this.basicInfo.ruleDescription = res.data.data.description
}
})
}
},
queryEvent () {
axios.get(api.detection.securityEvent.relationEvent, {
params: {
// startTime: this.detection.startTime,
unbiasedTime: this.detection.startTime,
offenderIp: this.detection.offenderIp,
victimIp: this.detection.victimIp,
biasSecond: 3600
}
}).then((response) => {
if (response.status === 200) {
this.events = response.data.data.result.sort((e1, e2) => e1.startTime - e2.startTime)
} else {
this.events = []
}
})
},
goDetail (type, name) {
if (name) {
const { href } = this.$router.resolve({
path: '/entityDetail',
query: {
entityType: type,
entityName: name
}
})
window.open(href, '_blank')
}
}
},
mounted () {
this.initEntityDetail()
this.queryEvent()
}
}
</script>
<style scoped>
.row__label {
width: 176px;
}
.row__content {
width: calc(100% - 176px);
padding-right: 50px;
}
</style>