Skip to content

Commit

Permalink
Merge branch 'master' into fix-log-abilityid
Browse files Browse the repository at this point in the history
  • Loading branch information
clenk authored Sep 13, 2022
2 parents 329fe20 + 6eaeb74 commit 66c02c8
Show file tree
Hide file tree
Showing 18 changed files with 142 additions and 103 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/greetings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ name: Greetings

on: [pull_request, issues]

permissions:
contents: read

jobs:
greeting:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/first-interaction@v1
- uses: actions/first-interaction@bd33205aa5c96838e10fd65df0d01efd613677c1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Looks like your first issue -- we aim to respond to issues as quickly as possible. In the meantime, check out our documentation here: http://caldera.readthedocs.io/'
Expand Down
45 changes: 45 additions & 0 deletions .github/workflows/publish_docker_image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Create and publish a Docker image

on:
release:
types: [published]
workflow_dispatch:

permissions:
contents: read

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e

- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
12 changes: 9 additions & 3 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ on:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
strategy:
fail-fast: false
matrix:
Expand All @@ -25,12 +31,12 @@ jobs:
toxenv: py310,style,coverage-ci

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e
with:
submodules: recursive
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Setup python
uses: actions/setup-python@v2
uses: actions/setup-python@b55428b1882923874294fa556849718a1d7f2ca5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -44,7 +50,7 @@ jobs:
- name: Override Coverage Source Path for Sonar
run: sed -i "s/<source>\/home\/runner\/work\/caldera\/caldera/<source>\/github\/workspace/g" /home/runner/work/caldera/caldera/coverage.xml
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
uses: SonarSource/sonarcloud-github-action@156db6fef3e168e4972abb76de0b32bbce8ec77a
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
7 changes: 5 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: Security Checks

on: [push]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -19,11 +22,11 @@ jobs:
toxenv: safety

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e
with:
submodules: recursive
- name: Setup python
uses: actions/setup-python@v2
uses: actions/setup-python@b55428b1882923874294fa556849718a1d7f2ca5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ on:
schedule:
- cron: "0 0 * * *"

permissions:
contents: read

jobs:
stale:

runs-on: ubuntu-latest

permissions:
issues: write
pull-requests: write

steps:
- uses: actions/stale@v1
- uses: actions/stale@9c1b1c6e115ca2af09755448e0dbba24e5061cc8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-label: 'no-issue-activity'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ calderaenv/
conf/*.yml
!conf/default.yml
data/object_store
data/fact_store
data/results/*
!data/results/.gitkeep
data/payloads/*
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

# CALDERA&trade;

*Full documentation, training and use-cases can be found [here](https://caldera.readthedocs.io/en/latest/).*

CALDERA&trade; is a cyber security platform designed to easily automate adversary emulation, assist manual red-teams, and automate incident response.

It is built on the [MITRE ATT&CK™ framework](https://attack.mitre.org/) and is an active research project at MITRE.
Expand All @@ -18,6 +16,11 @@ The framework consists of two components:
an asynchronous command-and-control (C2) server with a REST API and a web interface.
2) **Plugins**. These repositories expand the core framework capabilities and providing additional functionality. Examples include agents, reporting, collections of TTPs and more.

## Resources and Socials
* 📜 [Documentation, training, and use-cases](https://caldera.readthedocs.io/en/latest/)
* ✍️ [CALDERA's blog](https://medium.com/@mitrecaldera/welcome-to-the-official-mitre-caldera-blog-page-f34c2cdfef09)
* 🌐 [Homepage](https://caldera.mitre.org)

## Plugins

:star: Create your own plugin! Plugin generator: **[Skeleton](https://github.com/mitre/skeleton)** :star:
Expand All @@ -26,7 +29,6 @@ an asynchronous command-and-control (C2) server with a REST API and a web interf
- **[Access](https://github.com/mitre/access)** (red team initial access tools and techniques)
- **[Atomic](https://github.com/mitre/atomic)** (Atomic Red Team project TTPs)
- **[Builder](https://github.com/mitre/builder)** (dynamically compile payloads)
- **[CalTack](https://github.com/mitre/caltack.git)** (embedded ATT&CK website)
- **[Compass](https://github.com/mitre/compass)** (ATT&CK visualizations)
- **[Debrief](https://github.com/mitre/debrief)** (operations insights)
- **[Emu](https://github.com/mitre/emu)** (CTID emulation plans)
Expand All @@ -45,6 +47,7 @@ an asynchronous command-and-control (C2) server with a REST API and a web interf
These plugins are ready to use but are not included by default:
- **[Pathfinder](https://github.com/center-for-threat-informed-defense/caldera_pathfinder)** (vulnerability scanning)
- **[SAML](https://github.com/mitre/saml)** (SAML authentication)
- **[CalTack](https://github.com/mitre/caltack.git)** (embedded ATT&CK website)

## Requirements

Expand Down
2 changes: 2 additions & 0 deletions app/objects/c_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ async def report(self, file_svc, data_svc, output=False):
step_report = dict(link_id=step.id,
ability_id=step.ability.ability_id,
command=step.command,
plaintext_command=step.plaintext_command,
delegated=step.decide.strftime(self.TIME_FORMAT),
run=step.finish,
status=step.status,
Expand Down Expand Up @@ -361,6 +362,7 @@ async def _load_objective(self, data_svc):

async def _convert_link_to_event_log(self, link, file_svc, data_svc, output=False):
event_dict = dict(command=link.command,
plaintext_command=link.plaintext_command,
delegated_timestamp=link.decide.strftime(self.TIME_FORMAT),
collected_timestamp=link.collect.strftime(self.TIME_FORMAT) if link.collect else None,
finished_timestamp=link.finish,
Expand Down
5 changes: 4 additions & 1 deletion app/objects/secondclass/c_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Meta:
id = ma.fields.String(missing='')
paw = ma.fields.String()
command = ma.fields.String()
plaintext_command = ma.fields.String()
status = ma.fields.Integer(missing=-3)
score = ma.fields.Integer(missing=0)
jitter = ma.fields.Integer(missing=0)
Expand Down Expand Up @@ -151,11 +152,12 @@ def status(self, value):
def is_global_variable(cls, variable):
return variable in cls.RESERVED

def __init__(self, command='', paw='', ability=None, executor=None, status=-3, score=0, jitter=0, cleanup=0, id='',
def __init__(self, command='', plaintext_command='', paw='', ability=None, executor=None, status=-3, score=0, jitter=0, cleanup=0, id='',
pin=0, host=None, deadman=False, used=None, relationships=None, agent_reported_time=None):
super().__init__()
self.id = str(id)
self.command = command
self.plaintext_command = plaintext_command
self.command_hash = None
self.paw = paw
self.host = host
Expand Down Expand Up @@ -222,6 +224,7 @@ def is_valid_status(self, status):
def replace_origin_link_id(self):
decoded_cmd = self.decode_bytes(self.command)
self.command = self.encode_string(decoded_cmd.replace(self.RESERVED['origin_link_id'], self.id))
self.plaintext_command = decoded_cmd

def _emit_status_change_event(self, from_status, to_status):
event_svc = BaseService.get_service('event_svc')
Expand Down
1 change: 1 addition & 0 deletions app/utility/base_planning_svc.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ async def obfuscate_commands(self, agent, obfuscator, links):
o = (await self.get_service('data_svc').locate('obfuscators', match=dict(name=obfuscator)))[0]
mod = o.load(agent)
for s_link in links:
s_link.plaintext_command = s_link.command
s_link.command = self.encode_string(mod.run(s_link))
return links

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ pyyaml>=5.1
cryptography>=3.2,<37.0.0; python_version <= '3.7'
cryptography>=3.2; python_version > '3.7'
websockets>=10.3
Sphinx==3.0.4
Sphinx==5.1.1
docutils==0.16 # Broken bullet lists in sphinx_rtd_theme https://github.com/readthedocs/sphinx_rtd_theme/issues/1115
sphinx_rtd_theme==0.4.3
recommonmark==0.6.0
myst-parser==0.18.0
marshmallow==3.5.1
dirhash==0.2.0
docker==4.2.0
Expand Down
1 change: 1 addition & 0 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def setup_logger(level=logging.DEBUG):
continue
else:
logging.getLogger(logger_name).setLevel(100)
logging.getLogger("markdown_it").setLevel(logging.WARNING)
logging.captureWarnings(True)


Expand Down
5 changes: 5 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ sonar.sources=./app

sonar.python.version=3.7,3.8,3.9,3.10
sonar.python.coverage.reportPaths=coverage.xml

# Make an exception to Link's constructor, since it requires a refactor to pass
sonar.issue.ignore.multicriteria=e1
sonar.issue.ignore.multicriteria.e1.ruleKey=python:S107
sonar.issue.ignore.multicriteria.e1.resourceKey=app/objects/secondclass/c_link.py
70 changes: 7 additions & 63 deletions static/js/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,15 @@ function sortAlphabetically(list) {
})
}

function sanitize(unsafeMsg) {
const parser = new DOMParser();
let doc = parser.parseFromString(unsafeMsg, 'text/html');
return doc.body.innerText;
}

function toast(message, success) {
bulmaToast.toast({
message: `<span class="icon"><i class="fas fa-${success ? 'check' : 'exclamation'}"></i></span> ${message}`,
message: `<span class="icon"><i class="fas fa-${success ? 'check' : 'exclamation'}"></i></span> ${sanitize(message)}`,
type: `toast ${success ? 'is-success' : 'is-danger'}`,
position: 'bottom-right',
duration: '3000',
Expand Down Expand Up @@ -250,41 +256,6 @@ function uuidv4() {
});
}

// TODO: JQuery functions

function showHide(show, hide) {
$(show).each(function () {
$(this).prop('disabled', false).css('opacity', 1.0)
});
$(hide).each(function () {
$(this).prop('disabled', true).css('opacity', 0.5)
});
}

function validateFormState(conditions, selector) {
(conditions) ?
updateButtonState(selector, 'valid') :
updateButtonState(selector, 'invalid');
}

function updateButtonState(selector, state) {
(state === 'valid') ?
$(selector).attr('class', 'button-success atomic-button') :
$(selector).attr('class', 'button-notready atomic-button');
}

function stream(msg, speak = false) {
let streamer = $('#streamer');
if (streamer.text() != msg) {
streamer.fadeOut(function () {
if (speak) {
window.speechSynthesis.speak(new SpeechSynthesisUtterance(msg));
}
$(this).text(msg).fadeIn(1000);
});
}
}

/* SECTIONS */

// Alternative to JQuery parseHTML(keepScripts=true)
Expand All @@ -308,33 +279,6 @@ function removeSection(identifier) {
$('#' + identifier).remove();
}

/* AUTOMATIC functions for all pages */

$(document).ready(function () {
$(document).find("select").each(function () {
if (!$(this).hasClass('avoid-alphabetizing')) {
alphabetize_dropdown($(this));
let observer = new MutationObserver(function (mutations, obs) {
obs.disconnect();
alphabetize_dropdown($(mutations[0].target));
obs.observe(mutations[0].target, {childList: true});
});
observer.observe(this, {childList: true});
}
});
});

function alphabetize_dropdown(obj) {
let selected_val = $(obj).children("option:selected").val();
let disabled = $(obj).find('option:disabled');
let opts_list = $(obj).find('option:enabled').clone(true);
opts_list.sort(function (a, b) {
return a.text.toLowerCase() == b.text.toLowerCase() ? 0 : a.text.toLowerCase() < b.text.toLowerCase() ? -1 : 1;
});
$(obj).empty().append(opts_list).prepend(disabled);
obj.val(selected_val);
}

function b64DecodeUnicode(str) { //https://stackoverflow.com/a/30106551
if (str != null) {
// An error check is needed in case the wrong codec (i.e. not UTF-8) was used at source
Expand Down
1 change: 1 addition & 0 deletions templates/configurations.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ <h2>Configuration</h2>
},

enablePlugin(pluginName) {
pluginName = sanitize(pluginName);
let requestBody = {
value: pluginName,
prop: 'plugin'
Expand Down
Loading

0 comments on commit 66c02c8

Please sign in to comment.