diff --git a/attack-theme/static/images/ATTACKCon-4.png b/attack-theme/static/images/ATTACKCon-4.png deleted file mode 100644 index bb0e96c140d..00000000000 Binary files a/attack-theme/static/images/ATTACKCon-4.png and /dev/null differ diff --git a/attack-theme/static/images/ATTACKCon-5.png b/attack-theme/static/images/ATTACKCon-5.png deleted file mode 100644 index b67bf678553..00000000000 Binary files a/attack-theme/static/images/ATTACKCon-5.png and /dev/null differ diff --git a/attack-theme/static/images/ATTACKcon-sponsors-final.jpg b/attack-theme/static/images/ATTACKcon-sponsors-final.jpg deleted file mode 100644 index 42291ec88e4..00000000000 Binary files a/attack-theme/static/images/ATTACKcon-sponsors-final.jpg and /dev/null differ diff --git a/attack-theme/static/images/attackcon2-sponsors/ATTACKIQ.png b/attack-theme/static/images/attackcon/attackcon-2.0/ATTACKIQ.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/ATTACKIQ.png rename to attack-theme/static/images/attackcon/attackcon-2.0/ATTACKIQ.png diff --git a/attack-theme/static/images/attackcon2-sponsors/CISCO.png b/attack-theme/static/images/attackcon/attackcon-2.0/CISCO.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/CISCO.png rename to attack-theme/static/images/attackcon/attackcon-2.0/CISCO.png diff --git a/attack-theme/static/images/attackcon2-sponsors/CrowdstrikeLogo.png b/attack-theme/static/images/attackcon/attackcon-2.0/CrowdstrikeLogo.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/CrowdstrikeLogo.png rename to attack-theme/static/images/attackcon/attackcon-2.0/CrowdstrikeLogo.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Cybereason.png b/attack-theme/static/images/attackcon/attackcon-2.0/Cybereason.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Cybereason.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Cybereason.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Digital-Shadows.png b/attack-theme/static/images/attackcon/attackcon-2.0/Digital-Shadows.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Digital-Shadows.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Digital-Shadows.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Endgame_Logo.png b/attack-theme/static/images/attackcon/attackcon-2.0/Endgame_Logo.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Endgame_Logo.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Endgame_Logo.png diff --git a/attack-theme/static/images/attackcon2-sponsors/McAfee.png b/attack-theme/static/images/attackcon/attackcon-2.0/McAfee.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/McAfee.png rename to attack-theme/static/images/attackcon/attackcon-2.0/McAfee.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Microsoft.png b/attack-theme/static/images/attackcon/attackcon-2.0/Microsoft.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Microsoft.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Microsoft.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Praetorian-logo.png b/attack-theme/static/images/attackcon/attackcon-2.0/Praetorian-logo.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Praetorian-logo.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Praetorian-logo.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Red_Canary.png b/attack-theme/static/images/attackcon/attackcon-2.0/Red_Canary.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Red_Canary.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Red_Canary.png diff --git a/attack-theme/static/images/attackcon2-sponsors/SafeBreachLogo.png b/attack-theme/static/images/attackcon/attackcon-2.0/SafeBreachLogo.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/SafeBreachLogo.png rename to attack-theme/static/images/attackcon/attackcon-2.0/SafeBreachLogo.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Sycthe-logo.png b/attack-theme/static/images/attackcon/attackcon-2.0/Sycthe-logo.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Sycthe-logo.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Sycthe-logo.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Syncurity-Logo.png b/attack-theme/static/images/attackcon/attackcon-2.0/Syncurity-Logo.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Syncurity-Logo.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Syncurity-Logo.png diff --git a/attack-theme/static/images/attackcon2-sponsors/TREND-Micro.png b/attack-theme/static/images/attackcon/attackcon-2.0/TREND-Micro.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/TREND-Micro.png rename to attack-theme/static/images/attackcon/attackcon-2.0/TREND-Micro.png diff --git a/attack-theme/static/images/attackcon2-sponsors/Threat_Quotient.png b/attack-theme/static/images/attackcon/attackcon-2.0/Threat_Quotient.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/Threat_Quotient.png rename to attack-theme/static/images/attackcon/attackcon-2.0/Threat_Quotient.png diff --git a/attack-theme/static/images/attackcon2-sponsors/VMRAY.png b/attack-theme/static/images/attackcon/attackcon-2.0/VMRAY.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/VMRAY.png rename to attack-theme/static/images/attackcon/attackcon-2.0/VMRAY.png diff --git a/attack-theme/static/images/attackcon2-sponsors/XMCyberv2.png b/attack-theme/static/images/attackcon/attackcon-2.0/XMCyberv2.png similarity index 100% rename from attack-theme/static/images/attackcon2-sponsors/XMCyberv2.png rename to attack-theme/static/images/attackcon/attackcon-2.0/XMCyberv2.png diff --git a/attack-theme/static/images/attackcon2-banner.png b/attack-theme/static/images/attackcon/attackcon-2.0/attackcon2-banner.png similarity index 100% rename from attack-theme/static/images/attackcon2-banner.png rename to attack-theme/static/images/attackcon/attackcon-2.0/attackcon2-banner.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/attackiq.png b/attack-theme/static/images/attackcon/attackcon-2018/attackiq.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/attackiq.png rename to attack-theme/static/images/attackcon/attackcon-2018/attackiq.png diff --git a/attack-theme/static/images/attckcon-banner.jpg b/attack-theme/static/images/attackcon/attackcon-2018/attckcon-banner.jpg similarity index 100% rename from attack-theme/static/images/attckcon-banner.jpg rename to attack-theme/static/images/attackcon/attackcon-2018/attckcon-banner.jpg diff --git a/attack-theme/static/images/attackcon2018-sponsors/crowdstrike.png b/attack-theme/static/images/attackcon/attackcon-2018/crowdstrike.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/crowdstrike.png rename to attack-theme/static/images/attackcon/attackcon-2018/crowdstrike.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/endgame.png b/attack-theme/static/images/attackcon/attackcon-2018/endgame.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/endgame.png rename to attack-theme/static/images/attackcon/attackcon-2018/endgame.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/mcafee.png b/attack-theme/static/images/attackcon/attackcon-2018/mcafee.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/mcafee.png rename to attack-theme/static/images/attackcon/attackcon-2018/mcafee.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/redcanary.png b/attack-theme/static/images/attackcon/attackcon-2018/redcanary.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/redcanary.png rename to attack-theme/static/images/attackcon/attackcon-2018/redcanary.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/safebreach.png b/attack-theme/static/images/attackcon/attackcon-2018/safebreach.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/safebreach.png rename to attack-theme/static/images/attackcon/attackcon-2018/safebreach.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/tripwire.png b/attack-theme/static/images/attackcon/attackcon-2018/tripwire.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/tripwire.png rename to attack-theme/static/images/attackcon/attackcon-2018/tripwire.png diff --git a/attack-theme/static/images/attackcon2018-sponsors/verodin.png b/attack-theme/static/images/attackcon/attackcon-2018/verodin.png similarity index 100% rename from attack-theme/static/images/attackcon2018-sponsors/verodin.png rename to attack-theme/static/images/attackcon/attackcon-2018/verodin.png diff --git a/attack-theme/static/images/ATTACKcon-3-Banner.png b/attack-theme/static/images/attackcon/attackcon-3.0/ATTACKcon-3-Banner.png similarity index 100% rename from attack-theme/static/images/ATTACKcon-3-Banner.png rename to attack-theme/static/images/attackcon/attackcon-3.0/ATTACKcon-3-Banner.png diff --git a/attack-theme/static/images/attackcon3-sponsors/analyst1.png b/attack-theme/static/images/attackcon/attackcon-3.0/analyst1.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/analyst1.png rename to attack-theme/static/images/attackcon/attackcon-3.0/analyst1.png diff --git a/attack-theme/static/images/attackcon3-sponsors/attackiq.png b/attack-theme/static/images/attackcon/attackcon-3.0/attackiq.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/attackiq.png rename to attack-theme/static/images/attackcon/attackcon-3.0/attackiq.png diff --git a/attack-theme/static/images/attackcon3-sponsors/cyber-ranges.png b/attack-theme/static/images/attackcon/attackcon-3.0/cyber-ranges.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/cyber-ranges.png rename to attack-theme/static/images/attackcon/attackcon-3.0/cyber-ranges.png diff --git a/attack-theme/static/images/attackcon3-sponsors/cyborg-security.png b/attack-theme/static/images/attackcon/attackcon-3.0/cyborg-security.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/cyborg-security.png rename to attack-theme/static/images/attackcon/attackcon-3.0/cyborg-security.png diff --git a/attack-theme/static/images/attackcon3-sponsors/kroll.png b/attack-theme/static/images/attackcon/attackcon-3.0/kroll.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/kroll.png rename to attack-theme/static/images/attackcon/attackcon-3.0/kroll.png diff --git a/attack-theme/static/images/attackcon3-sponsors/microsoft.png b/attack-theme/static/images/attackcon/attackcon-3.0/microsoft.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/microsoft.png rename to attack-theme/static/images/attackcon/attackcon-3.0/microsoft.png diff --git a/attack-theme/static/images/attackcon3-sponsors/pentera.png b/attack-theme/static/images/attackcon/attackcon-3.0/pentera.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/pentera.png rename to attack-theme/static/images/attackcon/attackcon-3.0/pentera.png diff --git a/attack-theme/static/images/attackcon3-sponsors/picus.png b/attack-theme/static/images/attackcon/attackcon-3.0/picus.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/picus.png rename to attack-theme/static/images/attackcon/attackcon-3.0/picus.png diff --git a/attack-theme/static/images/attackcon3-sponsors/trellix.jpeg b/attack-theme/static/images/attackcon/attackcon-3.0/trellix.jpeg similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/trellix.jpeg rename to attack-theme/static/images/attackcon/attackcon-3.0/trellix.jpeg diff --git a/attack-theme/static/images/attackcon3-sponsors/trend-micro.png b/attack-theme/static/images/attackcon/attackcon-3.0/trend-micro.png similarity index 100% rename from attack-theme/static/images/attackcon3-sponsors/trend-micro.png rename to attack-theme/static/images/attackcon/attackcon-3.0/trend-micro.png diff --git a/attack-theme/static/images/attackcon4/ATTACKCON_4.0_banner.png b/attack-theme/static/images/attackcon/attackcon-4.0/ATTACKCON_4.0_banner.png similarity index 100% rename from attack-theme/static/images/attackcon4/ATTACKCON_4.0_banner.png rename to attack-theme/static/images/attackcon/attackcon-4.0/ATTACKCON_4.0_banner.png diff --git a/attack-theme/static/images/attackcon4/analyst1.png b/attack-theme/static/images/attackcon/attackcon-4.0/analyst1.png similarity index 100% rename from attack-theme/static/images/attackcon4/analyst1.png rename to attack-theme/static/images/attackcon/attackcon-4.0/analyst1.png diff --git a/attack-theme/static/images/attackcon4/ardalyst.png b/attack-theme/static/images/attackcon/attackcon-4.0/ardalyst.png similarity index 100% rename from attack-theme/static/images/attackcon4/ardalyst.png rename to attack-theme/static/images/attackcon/attackcon-4.0/ardalyst.png diff --git a/attack-theme/static/images/attackcon4/cyware.png b/attack-theme/static/images/attackcon/attackcon-4.0/cyware.png similarity index 100% rename from attack-theme/static/images/attackcon4/cyware.png rename to attack-theme/static/images/attackcon/attackcon-4.0/cyware.png diff --git a/attack-theme/static/images/attackcon4/interpres.png b/attack-theme/static/images/attackcon/attackcon-4.0/interpres.png similarity index 100% rename from attack-theme/static/images/attackcon4/interpres.png rename to attack-theme/static/images/attackcon/attackcon-4.0/interpres.png diff --git a/attack-theme/static/images/attackcon4/opentext.png b/attack-theme/static/images/attackcon/attackcon-4.0/opentext.png similarity index 100% rename from attack-theme/static/images/attackcon4/opentext.png rename to attack-theme/static/images/attackcon/attackcon-4.0/opentext.png diff --git a/attack-theme/static/images/attackcon4/pentera.png b/attack-theme/static/images/attackcon/attackcon-4.0/pentera.png similarity index 100% rename from attack-theme/static/images/attackcon4/pentera.png rename to attack-theme/static/images/attackcon/attackcon-4.0/pentera.png diff --git a/attack-theme/static/images/attackcon4/prelude.png b/attack-theme/static/images/attackcon/attackcon-4.0/prelude.png similarity index 100% rename from attack-theme/static/images/attackcon4/prelude.png rename to attack-theme/static/images/attackcon/attackcon-4.0/prelude.png diff --git a/attack-theme/static/images/attackcon4/safebreach.png b/attack-theme/static/images/attackcon/attackcon-4.0/safebreach.png similarity index 100% rename from attack-theme/static/images/attackcon4/safebreach.png rename to attack-theme/static/images/attackcon/attackcon-4.0/safebreach.png diff --git a/attack-theme/static/images/attackcon4/thirdwave.png b/attack-theme/static/images/attackcon/attackcon-4.0/thirdwave.png similarity index 100% rename from attack-theme/static/images/attackcon4/thirdwave.png rename to attack-theme/static/images/attackcon/attackcon-4.0/thirdwave.png diff --git a/attack-theme/static/images/attackcon4/tidalcyber.png b/attack-theme/static/images/attackcon/attackcon-4.0/tidalcyber.png similarity index 100% rename from attack-theme/static/images/attackcon4/tidalcyber.png rename to attack-theme/static/images/attackcon/attackcon-4.0/tidalcyber.png diff --git a/attack-theme/static/images/attackcon4/trendmicro.png b/attack-theme/static/images/attackcon/attackcon-4.0/trendmicro.png similarity index 100% rename from attack-theme/static/images/attackcon4/trendmicro.png rename to attack-theme/static/images/attackcon/attackcon-4.0/trendmicro.png diff --git a/attack-theme/static/images/attackcon4/vectr.png b/attack-theme/static/images/attackcon/attackcon-4.0/vectr.png similarity index 100% rename from attack-theme/static/images/attackcon4/vectr.png rename to attack-theme/static/images/attackcon/attackcon-4.0/vectr.png diff --git a/attack-theme/static/images/attackcon5/ATTACKCON_5.0_banner.png b/attack-theme/static/images/attackcon/attackcon-5.0/ATTACKCON_5.0_banner.png similarity index 100% rename from attack-theme/static/images/attackcon5/ATTACKCON_5.0_banner.png rename to attack-theme/static/images/attackcon/attackcon-5.0/ATTACKCON_5.0_banner.png diff --git a/attack-theme/static/images/attackcon5/mitreengenuity.png b/attack-theme/static/images/attackcon/attackcon-5.0/mitreengenuity.png similarity index 100% rename from attack-theme/static/images/attackcon5/mitreengenuity.png rename to attack-theme/static/images/attackcon/attackcon-5.0/mitreengenuity.png diff --git a/attack-theme/static/images/attackcon5/pentera.png b/attack-theme/static/images/attackcon/attackcon-5.0/pentera.png similarity index 100% rename from attack-theme/static/images/attackcon5/pentera.png rename to attack-theme/static/images/attackcon/attackcon-5.0/pentera.png diff --git a/attack-theme/static/images/attackcon5/redcanary.png b/attack-theme/static/images/attackcon/attackcon-5.0/redcanary.png similarity index 100% rename from attack-theme/static/images/attackcon5/redcanary.png rename to attack-theme/static/images/attackcon/attackcon-5.0/redcanary.png diff --git a/attack-theme/static/images/attackcon5/safebreach.png b/attack-theme/static/images/attackcon/attackcon-5.0/safebreach.png similarity index 100% rename from attack-theme/static/images/attackcon5/safebreach.png rename to attack-theme/static/images/attackcon/attackcon-5.0/safebreach.png diff --git a/attack-theme/static/images/attackcon5/socradar.png b/attack-theme/static/images/attackcon/attackcon-5.0/socradar.png similarity index 100% rename from attack-theme/static/images/attackcon5/socradar.png rename to attack-theme/static/images/attackcon/attackcon-5.0/socradar.png diff --git a/attack-theme/static/images/attackcon5/tidalcyber.png b/attack-theme/static/images/attackcon/attackcon-5.0/tidalcyber.png similarity index 100% rename from attack-theme/static/images/attackcon5/tidalcyber.png rename to attack-theme/static/images/attackcon/attackcon-5.0/tidalcyber.png diff --git a/attack-theme/static/images/attackcon5/trendmicro.png b/attack-theme/static/images/attackcon/attackcon-5.0/trendmicro.png similarity index 100% rename from attack-theme/static/images/attackcon5/trendmicro.png rename to attack-theme/static/images/attackcon/attackcon-5.0/trendmicro.png diff --git a/attack-theme/static/images/attackcon6/ATTACKCON_6.0_banner.png b/attack-theme/static/images/attackcon/attackcon-6.0/ATTACKCON_6.0_banner.png similarity index 100% rename from attack-theme/static/images/attackcon6/ATTACKCON_6.0_banner.png rename to attack-theme/static/images/attackcon/attackcon-6.0/ATTACKCON_6.0_banner.png diff --git a/attack-theme/static/images/attackcon6/cyberdefensemagazine.jpg b/attack-theme/static/images/attackcon/attackcon-6.0/cyberdefensemagazine.jpg similarity index 100% rename from attack-theme/static/images/attackcon6/cyberdefensemagazine.jpg rename to attack-theme/static/images/attackcon/attackcon-6.0/cyberdefensemagazine.jpg diff --git a/attack-theme/static/images/attackcon6/deeptempo.png b/attack-theme/static/images/attackcon/attackcon-6.0/deeptempo.png similarity index 100% rename from attack-theme/static/images/attackcon6/deeptempo.png rename to attack-theme/static/images/attackcon/attackcon-6.0/deeptempo.png diff --git a/attack-theme/static/images/attackcon6/feedly.png b/attack-theme/static/images/attackcon/attackcon-6.0/feedly.png similarity index 100% rename from attack-theme/static/images/attackcon6/feedly.png rename to attack-theme/static/images/attackcon/attackcon-6.0/feedly.png diff --git a/attack-theme/static/images/attackcon6/material.png b/attack-theme/static/images/attackcon/attackcon-6.0/material.png similarity index 100% rename from attack-theme/static/images/attackcon6/material.png rename to attack-theme/static/images/attackcon/attackcon-6.0/material.png diff --git a/attack-theme/static/images/attackcon6/redcanary.png b/attack-theme/static/images/attackcon/attackcon-6.0/redcanary.png similarity index 100% rename from attack-theme/static/images/attackcon6/redcanary.png rename to attack-theme/static/images/attackcon/attackcon-6.0/redcanary.png diff --git a/attack-theme/static/images/attackcon6/safebreach.png b/attack-theme/static/images/attackcon/attackcon-6.0/safebreach.png similarity index 100% rename from attack-theme/static/images/attackcon6/safebreach.png rename to attack-theme/static/images/attackcon/attackcon-6.0/safebreach.png diff --git a/attack-theme/static/images/attackcon6/securityrisk.png b/attack-theme/static/images/attackcon/attackcon-6.0/securityrisk.png similarity index 100% rename from attack-theme/static/images/attackcon6/securityrisk.png rename to attack-theme/static/images/attackcon/attackcon-6.0/securityrisk.png diff --git a/attack-theme/static/images/attackcon6/specterops.png b/attack-theme/static/images/attackcon/attackcon-6.0/specterops.png similarity index 100% rename from attack-theme/static/images/attackcon6/specterops.png rename to attack-theme/static/images/attackcon/attackcon-6.0/specterops.png diff --git a/attack-theme/static/images/attackcon6/threatconnect.png b/attack-theme/static/images/attackcon/attackcon-6.0/threatconnect.png similarity index 100% rename from attack-theme/static/images/attackcon6/threatconnect.png rename to attack-theme/static/images/attackcon/attackcon-6.0/threatconnect.png diff --git a/attack-theme/static/images/attackcon6/tidalcyber.png b/attack-theme/static/images/attackcon/attackcon-6.0/tidalcyber.png similarity index 100% rename from attack-theme/static/images/attackcon6/tidalcyber.png rename to attack-theme/static/images/attackcon/attackcon-6.0/tidalcyber.png diff --git a/attack-theme/static/images/attackcon6/trendmicro.png b/attack-theme/static/images/attackcon/attackcon-6.0/trendmicro.png similarity index 100% rename from attack-theme/static/images/attackcon6/trendmicro.png rename to attack-theme/static/images/attackcon/attackcon-6.0/trendmicro.png diff --git a/attack-theme/static/images/attackcon6/vmray.png b/attack-theme/static/images/attackcon/attackcon-6.0/vmray.png similarity index 100% rename from attack-theme/static/images/attackcon6/vmray.png rename to attack-theme/static/images/attackcon/attackcon-6.0/vmray.png diff --git a/attack-theme/static/images/attackcon/attackcon-7.0/attackcon7-logo.png b/attack-theme/static/images/attackcon/attackcon-7.0/attackcon7-logo.png new file mode 100644 index 00000000000..307223941b2 Binary files /dev/null and b/attack-theme/static/images/attackcon/attackcon-7.0/attackcon7-logo.png differ diff --git a/attack-theme/static/images/ATTACKcon_power_hour.png b/attack-theme/static/images/attackcon/attackcon-power-hour/ATTACKcon_power_hour.png similarity index 100% rename from attack-theme/static/images/ATTACKcon_power_hour.png rename to attack-theme/static/images/attackcon/attackcon-power-hour/ATTACKcon_power_hour.png diff --git a/attack-theme/static/images/attckcon-banner-slim.jpg b/attack-theme/static/images/attckcon-banner-slim.jpg deleted file mode 100644 index 6203fb78c59..00000000000 Binary files a/attack-theme/static/images/attckcon-banner-slim.jpg and /dev/null differ diff --git a/attack-theme/templates/general/base-template.html b/attack-theme/templates/general/base-template.html index f5e0e7e72f5..c960c51d76b 100644 --- a/attack-theme/templates/general/base-template.html +++ b/attack-theme/templates/general/base-template.html @@ -3,12 +3,12 @@ {# base.html should be ignored and all changes must be applied to base-template.html instead. #} {% set BANNER_ENABLED = ${BANNER_ENABLED} %} -{% set BANNER_MESSAGE = "${BANNER_MESSAGE}" %} -{% set CONTENT_VERSION = "${CONTENT_VERSION}" -%} -{% set WEBSITE_VERSION = "${WEBSITE_VERSION}" -%} -{% set CHANGELOG_LOCATION = "${CHANGELOG_LOCATION}" -%} -{% set LOGO_HEADER = "${LOGO_HEADER}" -%} -{% set LOGO_FOOTER = "${LOGO_FOOTER}" -%} +{% set BANNER_MESSAGE = ${BANNER_MESSAGE} %} +{% set CONTENT_VERSION = ${CONTENT_VERSION} -%} +{% set WEBSITE_VERSION = ${WEBSITE_VERSION} -%} +{% set CHANGELOG_LOCATION = ${CHANGELOG_LOCATION} -%} +{% set LOGO_HEADER = ${LOGO_HEADER} -%} +{% set LOGO_FOOTER = ${LOGO_FOOTER} -%} {% set NAVIGATION_MENU = ${NAVIGATION_MENU} -%} {% set ATTACK_BRANDING = ${ATTACK_BRANDING} -%} {% set RESOURCES = ${RESOURCES} -%} @@ -169,4 +169,4 @@ {% endblock %} - \ No newline at end of file + diff --git a/custom_jinja_filters.py b/custom_jinja_filters.py index 53e6127c42d..cd59c9e2ff1 100644 --- a/custom_jinja_filters.py +++ b/custom_jinja_filters.py @@ -2,6 +2,8 @@ import json import os import re +from datetime import datetime +from zoneinfo import ZoneInfo import markdown @@ -44,6 +46,15 @@ def escape_spaces(word): return "%20".join(word.split(" ")) +def format_cfp_deadline(deadline_et): + eastern_deadline = datetime.fromisoformat(deadline_et) + if eastern_deadline.tzinfo is None: + eastern_deadline = eastern_deadline.replace(tzinfo=ZoneInfo("America/New_York")) + eastern_deadline = eastern_deadline.astimezone(ZoneInfo("America/New_York")) + eastern_date = f"{eastern_deadline.strftime('%A, %B')} {eastern_deadline.day}, {eastern_deadline.year}" + return f"{eastern_date} at {eastern_deadline.strftime('%-I:%M %p ET')}" + + def clean_path(path): """Remove index.html from end of a path, add / if not at beginning.""" path = path.split("index.html")[0] diff --git a/data/attackcon.json b/data/attackcon.json index 9b040b6a64a..e09d4a7e4e5 100644 --- a/data/attackcon.json +++ b/data/attackcon.json @@ -1,22 +1,40 @@ [ + { + "date": "October 2026", + "title": "ATT&CKcon 7.0", + "description": "ATT&CKcon 7.0 is scheduled for October 27-28, 2026. Join the MITRE ATT&CK community in McLean or virtually for the next annual conference led by the MITRE ATT&CK team. More details will be shared on the event site as they become available.", + "banner_img": "/theme/images/attackcon/attackcon-7.0/attackcon7-logo.png", + "banner_img_max_width": "32rem", + "event_dates": "October 27-28, 2026", + "event_location": "McLean, VA and virtual", + "event_link": "https://na.eventscloud.com/mitreattack7/", + "cfp_link": "https://www.openconf.org/ATTACKcon2026/openconf.php", + "cfp_deadline_et": "2026-07-02T20:00:00-04:00" + }, { "date": "October 2025", "title": "ATT&CKcon 6.0", "description": "We’re grateful to everyone who joined ATT&CKcon 6.0!

This year’s program featured another outstanding lineup of speakers who shared fresh perspectives and real-world experiences, enriching the knowledge of our ATT&CK community. We encourage you to keep watching and sharing these insightful sessions!

", - "banner_img": "/theme/images/attackcon6/ATTACKCON_6.0_banner.png", + "banner_img": "/theme/images/attackcon/attackcon-6.0/ATTACKCON_6.0_banner.png", + "banner_img_max_width": "52rem", + "event_dates": "October 14-15, 2025", + "event_location": "McLean, VA and virtual", + "event_link": "https://na.eventscloud.com/attackcon6", + "cfp_link": "https://www.openconf.org/ATTACKCON2025/openconf.php", + "cfp_deadline_et": "2025-07-09T20:00:00-04:00", "sponsors_img_list": [ - "/theme/images/attackcon6/feedly.png", - "/theme/images/attackcon6/material.png", - "/theme/images/attackcon6/safebreach.png", - "/theme/images/attackcon6/securityrisk.png", - "/theme/images/attackcon6/specterops.png", - "/theme/images/attackcon6/threatconnect.png", - "/theme/images/attackcon6/tidalcyber.png", - "/theme/images/attackcon6/trendmicro.png", - "/theme/images/attackcon6/vmray.png", - "/theme/images/attackcon6/deeptempo.png", - "/theme/images/attackcon6/cyberdefensemagazine.jpg", - "/theme/images/attackcon6/redcanary.png" + "/theme/images/attackcon/attackcon-6.0/feedly.png", + "/theme/images/attackcon/attackcon-6.0/material.png", + "/theme/images/attackcon/attackcon-6.0/safebreach.png", + "/theme/images/attackcon/attackcon-6.0/securityrisk.png", + "/theme/images/attackcon/attackcon-6.0/specterops.png", + "/theme/images/attackcon/attackcon-6.0/threatconnect.png", + "/theme/images/attackcon/attackcon-6.0/tidalcyber.png", + "/theme/images/attackcon/attackcon-6.0/trendmicro.png", + "/theme/images/attackcon/attackcon-6.0/vmray.png", + "/theme/images/attackcon/attackcon-6.0/deeptempo.png", + "/theme/images/attackcon/attackcon-6.0/cyberdefensemagazine.jpg", + "/theme/images/attackcon/attackcon-6.0/redcanary.png" ], "presentations": [ { @@ -492,15 +510,20 @@ "date": "October 2024", "title": "ATT&CKcon 5.0", "description": "We are thrilled and express our gratitude to everyone who participated in ATT&CKcon 5.0!

This year we were privileged to have another range of speakers who shared their unique insights and experiences, further enriching the knowledge pool of our ATT&CK community. We invite you to continue to watch and share these insightful talks!

Click here to explore the talks from ATT&CKcon 5.0 on our YouTube playlist!", - "banner_img": "/theme/images/attackcon5/ATTACKCON_5.0_banner.png", + "banner_img": "/theme/images/attackcon/attackcon-5.0/ATTACKCON_5.0_banner.png", + "banner_img_max_width": "52rem", + "event_dates": "October 22-23, 2024", + "event_location": "McLean, VA and virtual", + "cfp_link": "https://www.openconf.org/attackcon2024/openconf.php", + "cfp_deadline_et": "2024-06-26T20:00:00-04:00", "sponsors_img_list": [ - "/theme/images/attackcon5/mitreengenuity.png", - "/theme/images/attackcon5/safebreach.png", - "/theme/images/attackcon5/socradar.png", - "/theme/images/attackcon5/tidalcyber.png", - "/theme/images/attackcon5/trendmicro.png", - "/theme/images/attackcon5/pentera.png", - "/theme/images/attackcon5/redcanary.png" + "/theme/images/attackcon/attackcon-5.0/mitreengenuity.png", + "/theme/images/attackcon/attackcon-5.0/safebreach.png", + "/theme/images/attackcon/attackcon-5.0/socradar.png", + "/theme/images/attackcon/attackcon-5.0/tidalcyber.png", + "/theme/images/attackcon/attackcon-5.0/trendmicro.png", + "/theme/images/attackcon/attackcon-5.0/pentera.png", + "/theme/images/attackcon/attackcon-5.0/redcanary.png" ], "presentations": [ { @@ -991,20 +1014,23 @@ "date": "October 2023", "title": "ATT&CKcon 4.0", "description": "We are thrilled and express our gratitude to everyone who participated in ATT&CKcon 4.0!

This year we were privileged to have another range of speakers who shared their unique insights and experiences, further enriching the knowledge pool of our ATT&CK community. We invite you to continue to watch and share these insightful talks!

Click here to explore the talks from ATT&CKcon 4.0 on our YouTube playlist!", - "banner_img": "/theme/images/attackcon4/ATTACKCON_4.0_banner.png", + "banner_img": "/theme/images/attackcon/attackcon-4.0/ATTACKCON_4.0_banner.png", + "banner_img_max_width": "52rem", + "event_dates": "October 24-25, 2023", + "event_location": "McLean, VA and virtual", "sponsors_img_list": [ - "/theme/images/attackcon4/analyst1.png", - "/theme/images/attackcon4/ardalyst.png", - "/theme/images/attackcon4/cyware.png", - "/theme/images/attackcon4/interpres.png", - "/theme/images/attackcon4/opentext.png", - "/theme/images/attackcon4/pentera.png", - "/theme/images/attackcon4/prelude.png", - "/theme/images/attackcon4/safebreach.png", - "/theme/images/attackcon4/thirdwave.png", - "/theme/images/attackcon4/trendmicro.png", - "/theme/images/attackcon4/vectr.png", - "/theme/images/attackcon4/tidalcyber.png" + "/theme/images/attackcon/attackcon-4.0/analyst1.png", + "/theme/images/attackcon/attackcon-4.0/ardalyst.png", + "/theme/images/attackcon/attackcon-4.0/cyware.png", + "/theme/images/attackcon/attackcon-4.0/interpres.png", + "/theme/images/attackcon/attackcon-4.0/opentext.png", + "/theme/images/attackcon/attackcon-4.0/pentera.png", + "/theme/images/attackcon/attackcon-4.0/prelude.png", + "/theme/images/attackcon/attackcon-4.0/safebreach.png", + "/theme/images/attackcon/attackcon-4.0/thirdwave.png", + "/theme/images/attackcon/attackcon-4.0/trendmicro.png", + "/theme/images/attackcon/attackcon-4.0/vectr.png", + "/theme/images/attackcon/attackcon-4.0/tidalcyber.png" ], "presentations": [ { @@ -1509,18 +1535,21 @@ "date": "March 2022", "title": "ATT&CKcon 3.0", "description": "", - "banner_img": "/theme/images/ATTACKcon-3-Banner.png", + "banner_img": "/theme/images/attackcon/attackcon-3.0/ATTACKcon-3-Banner.png", + "banner_img_max_width": "52rem", + "event_dates": "March 29-30, 2022", + "event_location": "McLean, VA and virtual", "sponsors_img_list": [ - "/theme/images/attackcon3-sponsors/analyst1.png", - "/theme/images/attackcon3-sponsors/attackiq.png", - "/theme/images/attackcon3-sponsors/cyber-ranges.png", - "/theme/images/attackcon3-sponsors/cyborg-security.png", - "/theme/images/attackcon3-sponsors/kroll.png", - "/theme/images/attackcon3-sponsors/microsoft.png", - "/theme/images/attackcon3-sponsors/pentera.png", - "/theme/images/attackcon3-sponsors/picus.png", - "/theme/images/attackcon3-sponsors/trellix.jpeg", - "/theme/images/attackcon3-sponsors/trend-micro.png" + "/theme/images/attackcon/attackcon-3.0/analyst1.png", + "/theme/images/attackcon/attackcon-3.0/attackiq.png", + "/theme/images/attackcon/attackcon-3.0/cyber-ranges.png", + "/theme/images/attackcon/attackcon-3.0/cyborg-security.png", + "/theme/images/attackcon/attackcon-3.0/kroll.png", + "/theme/images/attackcon/attackcon-3.0/microsoft.png", + "/theme/images/attackcon/attackcon-3.0/pentera.png", + "/theme/images/attackcon/attackcon-3.0/picus.png", + "/theme/images/attackcon/attackcon-3.0/trellix.jpeg", + "/theme/images/attackcon/attackcon-3.0/trend-micro.png" ], "presentations": [ { @@ -1879,7 +1908,10 @@ "date": "October 2020", "title": "ATT&CKcon Power Hour", "description": "Thank you to everyone who attended and spoke as ATT&CKcon went virtual in 2020. Broken into a series of four 1.5 hour virtual sessions, ATT&CKcon Power Hour talks have been viewed over 12,000 times. ATT&CKcon Power Hour brought us talks on areas of ATT&CK we haven't heard about before such as Cloud and Mobile as well as insights on how organizations are adapting to features such as sub-techniques. Please continue to watch and share these talks!", - "banner_img": "/theme/images/ATTACKcon_power_hour.png", + "banner_img": "/theme/images/attackcon/attackcon-power-hour/ATTACKcon_power_hour.png", + "banner_img_max_width": "52rem", + "event_dates": "October 2020 - January 2021", + "event_location": "Virtual", "presentations": [ { "title": "Starting Over with Sub-Techniques: Lessons Learned Remapping Detection Analytics", @@ -2166,25 +2198,28 @@ { "date": "October 2019", "title": "ATT&CKcon 2.0", - "banner_img": "/theme/images/attackcon2-banner.png", + "banner_img": "/theme/images/attackcon/attackcon-2.0/attackcon2-banner.png", + "banner_img_max_width": "52rem", + "event_dates": "October 29-30, 2019", + "event_location": "McLean, VA", "sponsors_img_list": [ - "/theme/images/attackcon2-sponsors/ATTACKIQ.png", - "/theme/images/attackcon2-sponsors/CISCO.png", - "/theme/images/attackcon2-sponsors/CrowdstrikeLogo.png", - "/theme/images/attackcon2-sponsors/Cybereason.png", - "/theme/images/attackcon2-sponsors/Digital-Shadows.png", - "/theme/images/attackcon2-sponsors/Endgame_Logo.png", - "/theme/images/attackcon2-sponsors/McAfee.png", - "/theme/images/attackcon2-sponsors/Microsoft.png", - "/theme/images/attackcon2-sponsors/Praetorian-logo.png", - "/theme/images/attackcon2-sponsors/Red_Canary.png", - "/theme/images/attackcon2-sponsors/SafeBreachLogo.png", - "/theme/images/attackcon2-sponsors/Syncurity-Logo.png", - "/theme/images/attackcon2-sponsors/Sycthe-logo.png", - "/theme/images/attackcon2-sponsors/TREND-Micro.png", - "/theme/images/attackcon2-sponsors/Threat_Quotient.png", - "/theme/images/attackcon2-sponsors/VMRAY.png", - "/theme/images/attackcon2-sponsors/XMCyberv2.png" + "/theme/images/attackcon/attackcon-2.0/ATTACKIQ.png", + "/theme/images/attackcon/attackcon-2.0/CISCO.png", + "/theme/images/attackcon/attackcon-2.0/CrowdstrikeLogo.png", + "/theme/images/attackcon/attackcon-2.0/Cybereason.png", + "/theme/images/attackcon/attackcon-2.0/Digital-Shadows.png", + "/theme/images/attackcon/attackcon-2.0/Endgame_Logo.png", + "/theme/images/attackcon/attackcon-2.0/McAfee.png", + "/theme/images/attackcon/attackcon-2.0/Microsoft.png", + "/theme/images/attackcon/attackcon-2.0/Praetorian-logo.png", + "/theme/images/attackcon/attackcon-2.0/Red_Canary.png", + "/theme/images/attackcon/attackcon-2.0/SafeBreachLogo.png", + "/theme/images/attackcon/attackcon-2.0/Syncurity-Logo.png", + "/theme/images/attackcon/attackcon-2.0/Sycthe-logo.png", + "/theme/images/attackcon/attackcon-2.0/TREND-Micro.png", + "/theme/images/attackcon/attackcon-2.0/Threat_Quotient.png", + "/theme/images/attackcon/attackcon-2.0/VMRAY.png", + "/theme/images/attackcon/attackcon-2.0/XMCyberv2.png" ], "presentations": [ { @@ -2699,16 +2734,19 @@ "title": "ATT&CKcon 2018", "description": "Thank you for all the passion and engagement that made ATT&CKcon such a success. Over 250 of you joined us in person at MITRE’s McLean campus for our first ever event that was live streamed to more than 1,000 people at its peak. Our videos have been viewed over 10,000 times already, and there’s a lot of energy around the community to keep improving the ATT&CK framework. Please continue to watch and share these presentations.", "blogpost": "https://medium.com/mitre-attack/attackcon-2018-501d62566233", - "banner_img": "/theme/images/attckcon-banner.jpg", + "banner_img": "/theme/images/attackcon/attackcon-2018/attckcon-banner.jpg", + "banner_img_max_width": "52rem", + "event_dates": "October 23-24, 2018", + "event_location": "McLean, VA", "sponsors_img_list": [ - "/theme/images/attackcon2018-sponsors/mcafee.png", - "/theme/images/attackcon2018-sponsors/attackiq.png", - "/theme/images/attackcon2018-sponsors/endgame.png", - "/theme/images/attackcon2018-sponsors/tripwire.png", - "/theme/images/attackcon2018-sponsors/safebreach.png", - "/theme/images/attackcon2018-sponsors/crowdstrike.png", - "/theme/images/attackcon2018-sponsors/redcanary.png", - "/theme/images/attackcon2018-sponsors/verodin.png" + "/theme/images/attackcon/attackcon-2018/mcafee.png", + "/theme/images/attackcon/attackcon-2018/attackiq.png", + "/theme/images/attackcon/attackcon-2018/endgame.png", + "/theme/images/attackcon/attackcon-2018/tripwire.png", + "/theme/images/attackcon/attackcon-2018/safebreach.png", + "/theme/images/attackcon/attackcon-2018/crowdstrike.png", + "/theme/images/attackcon/attackcon-2018/redcanary.png", + "/theme/images/attackcon/attackcon-2018/verodin.png" ], "presentations": [ { diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 7f8202358c3..bb43d6794d9 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -46,19 +46,7 @@ If you are only updating the banner and nothing else, follow these steps. 6. Commit and push changes to the `develop` branch. -7. Open a pull request from `develop` to `master` . - - * PR naming convention: "Update website to X.Y.Z" - -8. After the PR is accepted, tag the commit in the master branch and push the changes - - ```bash - git checkout master - git pull - git tag -a "website-vX.Y.Z" -m "website-vX.Y.Z" - git push - git push --tags - ``` +7. Open and accept the pull request from `develop` to `master` . ## ATT&CK Content updates diff --git a/modules/assets/assets_config.py b/modules/assets/assets_config.py index 49c583c4a21..0a6f327503c 100644 --- a/modules/assets/assets_config.py +++ b/modules/assets/assets_config.py @@ -10,7 +10,14 @@ asset_index_md = "Title: Asset overview\nTemplate: assets/assets-index\nsave_as: assets/index.html\ndata: " # String template for asset page -asset_md = Template("Title: ${name}\nTemplate: assets/asset\nsave_as: assets/${attack_id}/index.html\ndata: ") +asset_md = Template( + "Title: ${name}\n" + "Slug: asset-${attack_id}\n" + "url: /assets/${attack_id}/\n" + "Template: assets/asset\n" + "save_as: assets/${attack_id}/index.html\n" + "data: " +) # Path for templates assets_templates_path = "modules/assets/templates/" diff --git a/modules/campaigns/campaigns_config.py b/modules/campaigns/campaigns_config.py index 5d908dd6400..f4e24bcf560 100644 --- a/modules/campaigns/campaigns_config.py +++ b/modules/campaigns/campaigns_config.py @@ -13,7 +13,12 @@ # String template for campaign page campaign_md = Template( - "Title: ${name}\nTemplate: campaigns/campaign\nsave_as: campaigns/${attack_id}/index.html\ndata: " + "Title: ${name}\n" + "Slug: campaign-${attack_id}\n" + "url: /campaigns/${attack_id}/\n" + "Template: campaigns/campaign\n" + "save_as: campaigns/${attack_id}/index.html\n" + "data: " ) # Path for templates diff --git a/modules/datasources/datasources_config.py b/modules/datasources/datasources_config.py index 3d062782e77..975dff17c90 100644 --- a/modules/datasources/datasources_config.py +++ b/modules/datasources/datasources_config.py @@ -16,7 +16,12 @@ # String template for data source page datasource_md = Template( - "Title: ${name}\nTemplate: datasources/datasource\nsave_as: datasources/${attack_id}/index.html\ndata: " + "Title: ${name}\n" + "Slug: datasource-${attack_id}\n" + "url: /datasources/${attack_id}/\n" + "Template: datasources/datasource\n" + "save_as: datasources/${attack_id}/index.html\n" + "data: " ) # Path for templates diff --git a/modules/detectionstrategies/detectionstrategies_config.py b/modules/detectionstrategies/detectionstrategies_config.py index fbdf26d4ee3..ee2dad9d9c3 100644 --- a/modules/detectionstrategies/detectionstrategies_config.py +++ b/modules/detectionstrategies/detectionstrategies_config.py @@ -21,7 +21,12 @@ # String template for individual page detectionstrategy_md = Template( - "Title: ${name}\nTemplate: detectionstrategies/detectionstrategy\nsave_as: detectionstrategies/${attack_id}/index.html\ndata: " + "Title: ${name}\n" + "Slug: detectionstrategy-${attack_id}\n" + "url: /detectionstrategies/${attack_id}/\n" + "Template: detectionstrategies/detectionstrategy\n" + "save_as: detectionstrategies/${attack_id}/index.html\n" + "data: " ) sidebar_detectionstrategies_md = ( @@ -29,4 +34,4 @@ "Template: general/sidebar-template \n" "save_as: detectionstrategies/sidebar-detectionstrategies/index.html\n" "data: " -) \ No newline at end of file +) diff --git a/modules/groups/groups_config.py b/modules/groups/groups_config.py index a096ebf0367..e7aa4b5a670 100644 --- a/modules/groups/groups_config.py +++ b/modules/groups/groups_config.py @@ -11,7 +11,14 @@ group_index_md = "Title: Group overview\nTemplate: groups/groups-index\nsave_as: groups/index.html\ndata: " # String template for group page -group_md = Template("Title: ${name}\nTemplate: groups/group\nsave_as: groups/${attack_id}/index.html\ndata: ") +group_md = Template( + "Title: ${name}\n" + "Slug: group-${attack_id}\n" + "url: /groups/${attack_id}/\n" + "Template: groups/group\n" + "save_as: groups/${attack_id}/index.html\n" + "data: " +) # Path for templates groups_templates_path = "modules/groups/templates/" diff --git a/modules/matrices/matrices.py b/modules/matrices/matrices.py index d0b64796c46..859be5144b4 100644 --- a/modules/matrices/matrices.py +++ b/modules/matrices/matrices.py @@ -4,6 +4,7 @@ from loguru import logger from modules import site_config, util +from modules.util.buildhelpers import metadata_slug from . import matrices_config @@ -66,6 +67,7 @@ def generate_platform_matrices(matrix, notes, side_menu_data=None): data["descr"] = matrix["descr"] data["path"] = matrix["path"] + data["slug"] = metadata_slug("matrix", data["path"]) data["versioning_feature"] = site_config.check_versions_module() data["resources"] = site_config.check_resources_module() @@ -94,6 +96,7 @@ def generate_deprecated_matrix(matrix, side_menu_data=None): data["name"] = matrix["name"] data["domain"] = matrix["matrix"].split("-")[0] data["path"] = matrix["path"] + data["slug"] = metadata_slug("matrix", data["path"]) data["deprecated"] = True ms = util.relationshipgetters.get_ms() diff --git a/modules/matrices/matrices_config.py b/modules/matrices/matrices_config.py index 72eb0f2c1ed..626b6b588ba 100644 --- a/modules/matrices/matrices_config.py +++ b/modules/matrices/matrices_config.py @@ -19,7 +19,14 @@ ) # String template for main domain matrices -matrix_md = Template("Title: Matrix-${domain}\nTemplate: matrices/matrix\nsave_as: matrices/${path}/index.html\ndata: ") +matrix_md = Template( + "Title: Matrix-${domain}\n" + "Slug: ${slug}\n" + "url: /matrices/${path}/\n" + "Template: matrices/matrix\n" + "save_as: matrices/${path}/index.html\n" + "data: " +) # String template for platform matrices platform_md = Template( diff --git a/modules/mitigations/mitigations_config.py b/modules/mitigations/mitigations_config.py index 0671fdac535..eb69c20660a 100644 --- a/modules/mitigations/mitigations_config.py +++ b/modules/mitigations/mitigations_config.py @@ -22,6 +22,8 @@ # String template for domains mitigation_domain_md = Template( "Title: Mitigations\n" + "Slug: mitigations-${domain}\n" + "url: /mitigations/${domain}/\n" "Template: mitigations/mitigations-domain-index\n" "save_as: mitigations/${domain}/index.html\n" "data: " @@ -29,7 +31,12 @@ # String template for all mitigations mitigation_md = Template( - "Title: ${name}-${domain}\nTemplate: mitigations/mitigation\nsave_as: mitigations/${attack_id}/index.html\ndata: " + "Title: ${name}-${domain}\n" + "Slug: mitigation-${attack_id}\n" + "url: /mitigations/${attack_id}/\n" + "Template: mitigations/mitigation\n" + "save_as: mitigations/${attack_id}/index.html\n" + "data: " ) sidebar_mitigations_md = ( diff --git a/modules/redirections/redirections.py b/modules/redirections/redirections.py index f34e5134644..0b39cd6d208 100644 --- a/modules/redirections/redirections.py +++ b/modules/redirections/redirections.py @@ -93,6 +93,8 @@ def _write_redirect_file(data, generated_save_as): return generated_save_as.add(save_as) + data["slug"] = util.buildhelpers.metadata_slug("redirect", data["from"]) + data["url"] = util.buildhelpers.public_url_from_save_as(save_as) subs = site_config.redirect_md_index.substitute(data) redirect_file = os.path.join(site_config.redirects_markdown_path, f"{data['title']}.md") diff --git a/modules/resources/resources.py b/modules/resources/resources.py index 7ab5430972a..333872fb041 100644 --- a/modules/resources/resources.py +++ b/modules/resources/resources.py @@ -5,6 +5,8 @@ import shutil import urllib.parse from datetime import datetime +from pathlib import Path +from zoneinfo import ZoneInfo from loguru import logger @@ -159,6 +161,7 @@ def generate_attackcon_page(): with open(os.path.join(site_config.data_directory, "attackcon.json"), "r", encoding="utf8") as f: attackcon = json.load(f) attackcon = sorted(attackcon, key=lambda a: datetime.strptime(a["date"], "%B %Y"), reverse=True) + add_attackcon_cfp_status(attackcon) # Below code used to get a list of all attackcon children for i in range(len(attackcon)): @@ -197,6 +200,32 @@ def generate_attackcon_page(): md_file.write(attackcon_content) +def add_attackcon_cfp_status(attackcon, now=None): + """Add build-time CFP display status to ATT&CKcon records. + + Parameters + ---------- + attackcon : list + ATT&CKcon records loaded from ``data/attackcon.json``. + now : datetime, optional + Current time. Defaults to the current Eastern time. + """ + if now is None: + now = datetime.now(ZoneInfo("America/New_York")) + elif now.tzinfo is None: + now = now.replace(tzinfo=ZoneInfo("America/New_York")) + + for con in attackcon: + con["show_cfp"] = False + if "cfp_link" not in con or "cfp_deadline_et" not in con: + continue + + cfp_deadline = datetime.fromisoformat(con["cfp_deadline_et"]) + if cfp_deadline.tzinfo is None: + cfp_deadline = cfp_deadline.replace(tzinfo=ZoneInfo("America/New_York")) + con["show_cfp"] = now < cfp_deadline + + def generate_faq_page(): """Responsible for compiling faq json into faq markdown file for rendering on the HMTL.""" logger.info("Generating FAQ page") @@ -261,6 +290,13 @@ def generate_static_pages(): for static_page in os.listdir(static_pages_dir): with open(os.path.join(static_pages_dir, static_page), "r", encoding="utf8") as md: content = md.read() + slug = util.buildhelpers.metadata_slug("resource", Path(static_page).stem) + content = util.buildhelpers.ensure_metadata_line(content, "Slug", slug) + save_as = util.buildhelpers.get_save_as_metadata(content) + if save_as and not util.buildhelpers.has_metadata_line(content, "url"): + content = util.buildhelpers.ensure_metadata_line( + content, "url", util.buildhelpers.public_url_from_save_as(save_as) + ) if static_page.startswith("updates-"): with open( diff --git a/modules/resources/templates/attackcon-overview.html b/modules/resources/templates/attackcon-overview.html index fc8f1397337..fb7e3d13a9a 100644 --- a/modules/resources/templates/attackcon-overview.html +++ b/modules/resources/templates/attackcon-overview.html @@ -24,12 +24,50 @@

{{ con.title }}

{% set ifSponsor = "sponsors_img_list" in con %} {% if "banner_img" in con %} -

- ATT&CKcon Banner +

+ ATT&CKcon Banner

{% endif %} + {% if "event_dates" in con and "event_location" in con %} +
+
+

{{ con.title }} Event Details

+

Dates: {{ con.event_dates }}
Location: {{ con.event_location }} + {% if con.show_cfp %} +
Call for Proposal deadline: {{ con.cfp_deadline_et | format_cfp_deadline }} + {% endif %} +

+ {% if "event_link" in con %} +

Visit the official event site for registration, sponsorship, speaker, and attendee information.

+ + + + {% endif %} + {% if con.show_cfp %} + + + + {% endif %} +
+
+ {% endif %} + {% if "description" in con %}

{{con.description}}

@@ -44,6 +82,7 @@

{{ con.title }}

{% if "banner_img" in con %}
+ {% if "presentations" in con and con.presentations|length > 0 %}
Presentations
@@ -126,6 +165,10 @@
{% endfor %} + {% else %} +
Presentations
+

Presentation details are not available yet. Check the event site for current {{ con.title }} information.

+ {% endif %}
{% if "sponsors_img_list" in con %} @@ -153,4 +196,4 @@
Sponsors
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/modules/resources/templates/attackcon.html b/modules/resources/templates/attackcon.html index 66c37733bc8..eca0b8bde1b 100644 --- a/modules/resources/templates/attackcon.html +++ b/modules/resources/templates/attackcon.html @@ -31,43 +31,49 @@

ATT&CKcon

href="/resources/engage-with-attack/contact/">Engage with ATT&CK

+ {{contact_card.render( + "ATT&CKcon 7.0", + "/resources/attackcon/october-2026/", + "October 27th - 28th, 2026
McLean, VA and virtual", + invert_icon=True)}} {{contact_card.render( "ATT&CKcon 6.0", "/resources/attackcon/october-2025/", - "October 14th - 15th, 2025
McLean, VA", + "October 14th - 15th, 2025
McLean, VA and virtual", invert_icon=True)}} {{contact_card.render( "ATT&CKcon 5.0", "/resources/attackcon/october-2024/", - "October 22nd - 23rd, 2024
McLean, VA", invert_icon=True)}} - {{contact_card.render( - "ATT&CKcon 4.0", - "/resources/attackcon/october-2023/", - "October 24th - 25th, 2023
McLean, VA", + "October 22nd - 23rd, 2024
McLean, VA and virtual", invert_icon=True)}}
+ {{contact_card.render( + "ATT&CKcon 4.0", + "/resources/attackcon/october-2023/", + "October 24th - 25th, 2023
McLean, VA and virtual", + invert_icon=True)}} {{contact_card.render( "ATT&CKcon 3.0", "/resources/attackcon/march-2022/", - "March 29th - 30th, 2022
McLean, VA", + "March 29th - 30th, 2022
McLean, VA and virtual", invert_icon=True)}} {{contact_card.render( "ATT&CKcon PowerHour", "/resources/attackcon/october-2020/", "October 2020 - January 2021
Virtual", invert_icon=True)}} +
+ +
{{contact_card.render("ATT&CKcon 2.0", "/resources/attackcon/october-2019/", "October 29th - 30th, 2019
McLean, VA", invert_icon=True)}} -
-
{{contact_card.render("ATT&CKcon 2018", "/resources/attackcon/october-2018/", "October 23rd - 24th, 2018
McLean, VA", invert_icon=True)}} -
@@ -77,4 +83,4 @@

ATT&CKcon

{% block scripts %} {{ super () }} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/modules/site_config.py b/modules/site_config.py index fa98d6b268b..38fd61650c0 100644 --- a/modules/site_config.py +++ b/modules/site_config.py @@ -140,9 +140,23 @@ def set_subdirectory(subdirectory_str): # Redirect md string template redirect_md_index = Template( - "Title: ${title}\nTemplate: general/redirect-index\nRedirectLink: ${to}\nprivate: True\nsave_as: ${from}/index.html" + "Title: ${title}\n" + "Slug: ${slug}\n" + "url: ${url}\n" + "Template: general/redirect-index\n" + "RedirectLink: ${to}\n" + "private: True\n" + "save_as: ${from}/index.html" +) +redirect_md = Template( + "Title: ${title}\n" + "Slug: ${slug}\n" + "url: ${url}\n" + "Template: general/redirect-index\n" + "RedirectLink: ${to}\n" + "private: True\n" + "save_as: ${from}" ) -redirect_md = Template("Title: ${title}\nTemplate: general/redirect-index\nRedirectLink: ${to}\nprivate: True\nsave_as: ${from}") # Custom_alphabet used to sort list of dictionaries by domain name # depending on domain ordering diff --git a/modules/software/software_config.py b/modules/software/software_config.py index e399491f585..d909092b635 100644 --- a/modules/software/software_config.py +++ b/modules/software/software_config.py @@ -13,7 +13,14 @@ software_index_md = "Title: Software overview\nTemplate: software/software-index\nsave_as: software/index.html\ndata: " # String template for group page -software_md = Template("Title: ${name}\nTemplate: software/software\nsave_as: software/${attack_id}/index.html\ndata: ") +software_md = Template( + "Title: ${name}\n" + "Slug: software-${attack_id}\n" + "url: /software/${attack_id}/\n" + "Template: software/software\n" + "save_as: software/${attack_id}/index.html\n" + "data: " +) software_redirection_location = "modules/software/software_redirections.json" diff --git a/modules/tactics/tactics_config.py b/modules/tactics/tactics_config.py index 6ea0080172d..dd17c231e8d 100644 --- a/modules/tactics/tactics_config.py +++ b/modules/tactics/tactics_config.py @@ -11,12 +11,22 @@ # String template for domains tactic_domain_md = Template( - "Title: Tactics\nTemplate: tactics/tactics-domain-index\nsave_as: tactics/${domain}/index.html\ndata: " + "Title: Tactics\n" + "Slug: tactics-${domain}\n" + "url: /tactics/${domain}/\n" + "Template: tactics/tactics-domain-index\n" + "save_as: tactics/${domain}/index.html\n" + "data: " ) # String template for tactics tactic_md = Template( - "Title: ${name}-${domain}\nTemplate: tactics/tactic\nsave_as: tactics/${attack_id}/index.html\ndata: " + "Title: ${name}-${domain}\n" + "Slug: tactic-${attack_id}\n" + "url: /tactics/${attack_id}/\n" + "Template: tactics/tactic\n" + "save_as: tactics/${attack_id}/index.html\n" + "data: " ) # Tactics overview md template diff --git a/modules/techniques/techniques_config.py b/modules/techniques/techniques_config.py index 2615da5aa29..435d2c33a0f 100644 --- a/modules/techniques/techniques_config.py +++ b/modules/techniques/techniques_config.py @@ -11,12 +11,22 @@ # String template for all techniques technique_md = Template( - "Title: ${name}-${domain}\nTemplate: techniques/technique\nsave_as: techniques/${attack_id}/index.html\ndata: " + "Title: ${name}-${domain}\n" + "Slug: technique-${attack_id}\n" + "url: /techniques/${attack_id}/\n" + "Template: techniques/technique\n" + "save_as: techniques/${attack_id}/index.html\n" + "data: " ) # String template for domains technique_domain_md = Template( - "Title: Techniques\nTemplate: techniques/techniques-domain-index\nsave_as: techniques/${domain}/index.html\ndata: " + "Title: Techniques\n" + "Slug: techniques-${domain}\n" + "url: /techniques/${domain}/\n" + "Template: techniques/techniques-domain-index\n" + "save_as: techniques/${domain}/index.html\n" + "data: " ) # Overview md template @@ -33,6 +43,8 @@ # String template for all techniques sub_technique_md = Template( "Title: ${name}-${domain}\n" + "Slug: technique-${parent_id}-${sub_number}\n" + "url: /techniques/${parent_id}/${sub_number}/\n" "Template: techniques/technique\n" "save_as: techniques/${parent_id}/${sub_number}/index.html\n" "data: " diff --git a/modules/util/buildhelpers.py b/modules/util/buildhelpers.py index 5b74bd7fa5e..c6ac4699277 100644 --- a/modules/util/buildhelpers.py +++ b/modules/util/buildhelpers.py @@ -20,6 +20,63 @@ def timestamp(): return timestamp +def metadata_slug(*parts): + """Return a stable Pelican metadata slug from IDs or path parts.""" + text = "-".join(str(part) for part in parts if part) + text = text.replace("/", "-").replace(".", "-").replace("_", "-") + return "-".join(text.lower().split()) + + +def public_url_from_save_as(save_as): + """Return the public site URL represented by a Pelican save_as path.""" + path = save_as.strip().lstrip("/") + if path == "index.html": + return "/" + if path.endswith("/index.html"): + return "/" + path[: -len("index.html")] + return "/" + path + + +def has_metadata_line(content, field): + """Return whether content already has a Pelican metadata field.""" + return re.search(rf"^{re.escape(field)}\s*:", content, re.IGNORECASE | re.MULTILINE) is not None + + +def ensure_metadata_line(content, field, value): + """Insert a Pelican metadata line after Title when the field is absent.""" + if has_metadata_line(content, field): + return content + + line = f"{field}: {value}" + final_newline = content.endswith("\n") + lines = content.splitlines() + + for index, existing_line in enumerate(lines): + if re.match(r"^Title\s*:", existing_line, re.IGNORECASE): + lines.insert(index + 1, line) + updated_content = "\n".join(lines) + return updated_content + ("\n" if final_newline else "") + + return line + "\n" + content + + +def set_metadata_line(content, field, value): + """Set a Pelican metadata field, inserting it after Title when absent.""" + line = f"{field}: {value}" + pattern = rf"^{re.escape(field)}\s*:.*$" + if has_metadata_line(content, field): + return re.sub(pattern, line, content, count=1, flags=re.IGNORECASE | re.MULTILINE) + return ensure_metadata_line(content, field, value) + + +def get_save_as_metadata(content): + """Return the first save_as metadata value from a Markdown page.""" + match = re.search(r"^save_as\s*:\s*(.+?)\s*$", content, re.IGNORECASE | re.MULTILINE) + if match: + return match.group(1) + return None + + def get_created_and_modified_dates(obj): """Given an object, return the modified and created dates.""" dates = {} @@ -862,6 +919,12 @@ def generate_redirections(redirections_filename, redirect_md=None): os.mkdir(site_config.redirects_markdown_path) for obj in redirects: + if redirect_md == site_config.redirect_md: + save_as = obj["from"] + else: + save_as = f"{obj['from']}/index.html" + obj["slug"] = metadata_slug("redirect", obj["from"]) + obj["url"] = public_url_from_save_as(save_as) subs = redirect_md.substitute(obj) redirect_md_file = os.path.join(site_config.redirects_markdown_path, f"{obj['title']}.md") diff --git a/modules/website_build/website_build.py b/modules/website_build/website_build.py index 2fedc1f1003..22df249a3b8 100644 --- a/modules/website_build/website_build.py +++ b/modules/website_build/website_build.py @@ -2,6 +2,7 @@ import json import os import subprocess +from pathlib import Path from string import Template from loguru import logger @@ -131,15 +132,27 @@ def generate_base_html(): logger.debug(f"{banner_message=}") if site_config.args.attack_brand: - if website_build_config.base_page_data["BANNER_MESSAGE"].startswith("This is a custom instance"): + if banner_message.startswith("This is a custom instance"): website_build_config.base_page_data["BANNER_ENABLED"] = False + base_page_data = website_build_config.base_page_data.copy() + jinja_string_fields = [ + "BANNER_MESSAGE", + "CONTENT_VERSION", + "WEBSITE_VERSION", + "CHANGELOG_LOCATION", + "LOGO_HEADER", + "LOGO_FOOTER", + ] + for field in jinja_string_fields: + base_page_data[field] = json.dumps(base_page_data[field], ensure_ascii=False) + with open( os.path.join(website_build_config.template_dir, "base-template.html"), "r", encoding="utf8" ) as base_template_file: base_template_str = base_template_file.read() base_template = Template(base_template_str) - subs = base_template.substitute(website_build_config.base_page_data) + subs = base_template.substitute(base_page_data) with open(os.path.join(website_build_config.template_dir, "base.html"), "w", encoding="utf8") as base_file: base_file.write(subs) @@ -227,7 +240,9 @@ def generate_changelog_page(): def pelican_content(): + """Build the generated markdown content with Pelican.""" logger.info("Building website with Pelican") + normalize_generated_page_urls() pelican_cmd = "pelican content" if site_config.subdirectory: @@ -268,6 +283,24 @@ def pelican_content(): raise +def normalize_generated_page_urls(): + """Ensure generated Markdown page URLs match their save_as output paths.""" + pages_dir = Path(site_config.pages_dir) + if not pages_dir.exists(): + return + + for page in pages_dir.rglob("*.md"): + content = page.read_text(encoding="utf8") + save_as = util.buildhelpers.get_save_as_metadata(content) + if not save_as: + continue + + url = util.buildhelpers.public_url_from_save_as(save_as).lstrip("/") + updated_content = util.buildhelpers.set_metadata_line(content, "url", url) + if updated_content != content: + page.write_text(updated_content, encoding="utf8") + + def remove_pelican_settings(): """Remove pelican settings.""" logger.info("Removing additional Pelican settings") @@ -288,6 +321,13 @@ def generate_static_pages(): for static_page in os.listdir(static_pages_dir): with open(os.path.join(static_pages_dir, static_page), "r", encoding="utf8") as md: content = md.read() + slug = util.buildhelpers.metadata_slug("resource", Path(static_page).stem) + content = util.buildhelpers.ensure_metadata_line(content, "Slug", slug) + save_as = util.buildhelpers.get_save_as_metadata(content) + if save_as and not util.buildhelpers.has_metadata_line(content, "url"): + content = util.buildhelpers.ensure_metadata_line( + content, "url", util.buildhelpers.public_url_from_save_as(save_as) + ) with open( os.path.join(website_build_config.website_build_markdown_path, static_page), "w", encoding="utf8" diff --git a/pelicanconf.py b/pelicanconf.py index 98c9ae4ed01..377c8b7e141 100644 --- a/pelicanconf.py +++ b/pelicanconf.py @@ -67,6 +67,7 @@ "clean_path": custom_jinja_filters.clean_path, "remove_whitespace": custom_jinja_filters.remove_whitespace, "escape_spaces": custom_jinja_filters.escape_spaces, + "format_cfp_deadline": custom_jinja_filters.format_cfp_deadline, "stixToHTML": custom_jinja_filters.stixToHTML, "permalink": custom_jinja_filters.permalink, } diff --git a/website-banner.production b/website-banner.production index 347580b768b..43f654cd68a 100644 --- a/website-banner.production +++ b/website-banner.production @@ -1 +1 @@ -ATT&CK v19 has been released! Check out the blog post for more information. \ No newline at end of file +ATT&CKcon 7.0 is coming October 27-28, 2026. Learn more about ATT&CKcon 7.0 and submit your proposal.