diff --git a/CHANGELOG.md b/CHANGELOG.md index be3ce0f683..47ce1db5bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,25 @@ # Change Log -## [2.11.1](https://github.com/CERT-BDF/TheHive/tree/HEAD) (2017-05-17) +## [2.11.2](https://github.com/CERT-BDF/TheHive/tree/2.11.2) +[Full Changelog](https://github.com/CERT-BDF/TheHive/compare/2.11.1...2.11.2) +**Implemented enhancements:** + +- Visually distinguish between analyzed and non analyzer observables [\#224](https://github.com/CERT-BDF/TheHive/issues/224) +- Add Description Field to Alert Preview Modal [\#218](https://github.com/CERT-BDF/TheHive/issues/218) +- Show case severity in lists [\#188](https://github.com/CERT-BDF/TheHive/issues/188) + +**Fixed bugs:** + +- MISP synchronization - attributes are not retrieve [\#221](https://github.com/CERT-BDF/TheHive/issues/221) +- MISP synchronization - Alerts are wrongly updated [\#220](https://github.com/CERT-BDF/TheHive/issues/220) +- Cortex jobs from thehive fail silently [\#219](https://github.com/CERT-BDF/TheHive/issues/219) + +**Merged pull requests:** + +- Fixing links to docu repo [\#213](https://github.com/CERT-BDF/TheHive/pull/213) ([SHSauler](https://github.com/SHSauler)) + +## [2.11.1](https://github.com/CERT-BDF/TheHive/tree/2.11.1) (2017-05-17) [Full Changelog](https://github.com/CERT-BDF/TheHive/compare/2.11.0...2.11.1) **Implemented enhancements:** diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..bef8212009 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,37 @@ +TheHive is a scalable 3-in-1 open source and free security incident response platform designed to make life easier for SOCs, CSIRTs, CERTs and any information security practitioner dealing with security incidents that need to be investigated and acted upon swiftly. + +## Hardware Pre-requisites + +TheHive uses ElasticSearch to store data. Both software use a Java VM. We recommend using a virtual machine with 8vCPU, 8 +GB of RAM and 60 GB of disk. You can also use a physical machine with similar specifications. + +## What's New? + +- [Changelog](/CHANGELOG.md) +- [Migration guide](migration-guide.md) + +## Installation Guides + +TheHive can be installed using: +- An [RPM package](installation/rpm-guide.md) +- A [DEB package](installation/deb-guide.md) +- [Docker](installation/docker-guide.md) +- [Binary](installation/binary-guide.md) +- [Ansible script](https://github.com/drewstinnett/ansible-thehive) contributed by +[@drewstinnett](https://github.com/drewstinnett) + +TheHive can also be [built from sources](installation/build-guide.md). + +## Administration Guides + +- [Administrator's guide](admin/admin-guide.md) +- [Configuration guide](admin/configuration.md) +- [Updating](admin/updating.md) +- [Backup & Restore](admin/backup-restore.md) + +## Developer Guides + +- [API documentation](api/README.md) + +## Other +- [FAQ](FAQ.md) diff --git a/docs/installation/rpm-guide.md b/docs/installation/rpm-guide.md new file mode 100644 index 0000000000..f701a2a9a6 --- /dev/null +++ b/docs/installation/rpm-guide.md @@ -0,0 +1,19 @@ +# Installing TheHive Using an RPM Package + +TheHive's RPM packages are published on our Bintray repository. All packages are PGP signed using the key which ID is [562CBC1C](/PGP-PUBLIC-KEY). The key's fingerprint is: + +```0CD5 AC59 DE5C 5A8E 0EE1 3849 3D99 BB18 562C BC1C``` + +To intall TheHive from an RPM package, you'll need to begin by installing the RPM release package using the following command: +``` +yum install install https://dl.bintray.com/cert-bdf/rpm/thehive-project-release-1.0.0-3.noarch.rpm +``` +This will install TheHive Project's repository in `/etc/yum.repos.d/thehive-rpm.repo` and the GPG public key `in +/etc/pki/rpm-gpg/GPG-TheHive-Project`. + +Once done, you will able to install TheHive package using yum: +``` +yum install thehive +``` + +One installed, you should [install ElasticSearch](elasticsearch-guide.md) and [configure TheHive](../admin/configuration.md). diff --git a/package/debian/postinst b/package/debian/postinst index 37b8e3e60b..b58ef7e2fd 100755 --- a/package/debian/postinst +++ b/package/debian/postinst @@ -85,4 +85,4 @@ addUser thehive "" thehive "thehive daemon-user" "/bin/false" chown thehive:thehive /var/log/thehive chown root:thehive /etc/thehive/application.conf /etc/thehive/logback.xml chmod 0640 /etc/thehive/application.conf /etc/thehive/logback.xml -mkdir /opt/thehive/conf +mkdir -p /opt/thehive/conf diff --git a/thehive-misp/app/connectors/misp/JsonFormat.scala b/thehive-misp/app/connectors/misp/JsonFormat.scala index 79f806b534..5a27bb80d5 100644 --- a/thehive-misp/app/connectors/misp/JsonFormat.scala +++ b/thehive-misp/app/connectors/misp/JsonFormat.scala @@ -30,11 +30,13 @@ object JsonFormat { publishTimestamp ← (json \ "publish_timestamp").validate[String] publishDate = new Date(publishTimestamp.toLong * 1000) threatLevel ← (json \ "threat_level_id").validate[String] + isPublished ← (json \ "published").validate[Boolean] } yield MispAlert( org, eventId, date, publishDate, + isPublished, s"#$eventId ${info.trim}", s"Imported from MISP Event #$eventId, created at $date", threatLevel.toLong, @@ -43,7 +45,7 @@ object JsonFormat { "") } - implicit val mispAlertWrites: Writes[MispAlert] = Json.writes[MispAlert] + implicit val mispAlertWrites: Writes[MispAlert] = Json.writes[MispAlert].transform((_: JsValue).asInstanceOf[JsObject] - "isPublished") implicit val attributeReads: Reads[MispAttribute] = Reads(json ⇒ for { diff --git a/thehive-misp/app/connectors/misp/MispModel.scala b/thehive-misp/app/connectors/misp/MispModel.scala index 01e6a57bd4..c7d472eeab 100644 --- a/thehive-misp/app/connectors/misp/MispModel.scala +++ b/thehive-misp/app/connectors/misp/MispModel.scala @@ -7,6 +7,7 @@ case class MispAlert( sourceRef: String, date: Date, lastSyncDate: Date, + isPublished: Boolean, title: String, description: String, severity: Long, diff --git a/thehive-misp/app/connectors/misp/MispSrv.scala b/thehive-misp/app/connectors/misp/MispSrv.scala index 6cc545bec5..452efe2c35 100644 --- a/thehive-misp/app/connectors/misp/MispSrv.scala +++ b/thehive-misp/app/connectors/misp/MispSrv.scala @@ -67,7 +67,12 @@ case class MispConnection( private[MispConnection] lazy val logger = Logger(getClass) - logger.info(s"Add MISP connection $name ($baseUrl)\n\tproxy configuration: ${ws.proxy}") + logger.info( + s"""Add MISP connection $name + |\turl: $baseUrl + |\tproxy: ${ws.proxy} + |\tcase template: ${caseTemplate.getOrElse("")} + |\tartifact tags: ${artifactTags.mkString}""".stripMargin) private[misp] def apply(url: String) = ws.url(s"$baseUrl/$url") @@ -165,19 +170,21 @@ class MispSrv @Inject() ( // get related alert .mapAsyncUnordered(1) { case (mcfg, lastSyncDate, event) ⇒ + logger.trace(s"Looking for alert misp:${event.source}:${event.sourceRef}") alertSrv.get("misp", event.source, event.sourceRef) .map(a ⇒ (mcfg, lastSyncDate, event, a)) } .mapAsyncUnordered(1) { case (mcfg, lastSyncDate, event, alert) ⇒ + logger.trace(s"MISP synchro ${mcfg.name} last sync at $lastSyncDate, event ${event.sourceRef}, alert ${alert.fold("no alert")("alert" + _.alertId())}") logger.info(s"getting MISP event ${event.sourceRef}") - getAttributes(mcfg, event.sourceRef, Some(lastSyncDate)) + getAttributes(mcfg, event.sourceRef, alert.map(_ ⇒ lastSyncDate)) .map((mcfg, event, alert, _)) } .mapAsyncUnordered(1) { // if there is no related alert, create a new one case (mcfg, event, None, attrs) ⇒ - logger.info(s"MISP event ${event.sourceRef} has no related alert, create it") + logger.info(s"MISP event ${event.sourceRef} has no related alert, create it with ${attrs.size} observable(s)") val alertJson = Json.toJson(event).as[JsObject] + ("type" → JsString("misp")) + ("caseTemplate" → mcfg.caseTemplate.fold[JsValue](JsNull)(JsString)) + @@ -188,11 +195,12 @@ class MispSrv @Inject() ( // if a related alert exists, update it case (_, event, Some(alert), attrs) ⇒ - logger.info(s"MISP event ${event.sourceRef} has related alert, update it") + logger.info(s"MISP event ${event.sourceRef} has related alert, update it with ${attrs.size} observable(s)") val alertJson = Json.toJson(event).as[JsObject] - "type" - "source" - "sourceRef" - + "caseTemplate" - "date" + ("artifacts" → JsArray(attrs)) + ("status" → (if (!alert.follow()) Json.toJson(alert.status()) @@ -232,14 +240,17 @@ class MispSrv @Inject() ( logger.warn(s"Invalid MISP event format:\n${response.body}") Nil } - val events = eventJson.flatMap { j ⇒ - j.asOpt[MispAlert] - .map(_.copy(source = mispConnection.name)) - .orElse { - logger.warn(s"MISP event can't be parsed\n$j") - None - } - } + val events = eventJson + .flatMap { j ⇒ + j.asOpt[MispAlert] + .map(_.copy(source = mispConnection.name)) + .orElse { + logger.warn(s"MISP event can't be parsed\n$j") + None + } + } + .filter(event ⇒ event.isPublished && event.date.after(fromDate)) + val eventJsonSize = eventJson.size val eventsSize = events.size if (eventJsonSize != eventsSize) diff --git a/ui/app/styles/case.css b/ui/app/styles/case.css index bc3f7e1133..b109b7b793 100644 --- a/ui/app/styles/case.css +++ b/ui/app/styles/case.css @@ -70,7 +70,8 @@ table.case-list .case-tags { font-size: 12px !important; } -table.case-list .case-tags .label { +table.case-list .case-tags .label, +.case-tags .label { font-size: inherit !important; font-weight: normal; } diff --git a/ui/app/views/partials/alert/event.dialog.html b/ui/app/views/partials/alert/event.dialog.html index 5580f98304..04584c0a5b 100644 --- a/ui/app/views/partials/alert/event.dialog.html +++ b/ui/app/views/partials/alert/event.dialog.html @@ -1,5 +1,5 @@