Skip to content

Commit 8c0c310

Browse files
authored
Merge pull request #81 from cmu-sei/6_0_development
Release of v6.0
2 parents d7acbcf + b9b0174 commit 8c0c310

File tree

93 files changed

+3727
-1603
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+3727
-1603
lines changed

README.md

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
1-
![GHOSTS Logo](https://github.com/cmu-sei/GHOSTS/blob/master/assets/ghosts-logo.jpg)
2-
3-
Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms.
4-
5-
# GHOSTS NPC AUTOMATION
6-
7-
GHOSTS is a framework for highly-complex, realistic non-player character (NPC) orchestration. It essentially realistically mimics the behavior of the different types of people you might encounter on any array of different typical office or enterprise networks. The system makes it possible for cybersecurity experts to test their skills and realistically train to defend real networks with real NPC players operating on those networks doing the things we might expect them to do: Create documents, access systems, browse the web, click, run commands, and so on.
8-
9-
As a result of the system checks required in order for NPCs to be situationally aware, GHOSTS also does health reporting for all configured clients on a given instance.
10-
11-
## Key Links
12-
13-
[Installation and configuration information is maintained on our wiki](https://github.com/cmu-sei/GHOSTS/wiki)
14-
15-
[Don't hesitate to submit issues and feature requests here](https://github.com/cmu-sei/GHOSTS/issues)
16-
17-
## Platform Components
18-
19-
### Ghosts.Client (Windows)
20-
.NET Console app (but built as forms app so that it is hidden) - requires .NET framework v4.6.1 or higher. Client works on both Windows 7 and Windows 10.
21-
22-
### Ghosts.Client (Linux)
23-
dotnetcore app built to run silently. Client tested on centos, alpine and kali distributions. We typically use this for red teaming and "outside" traffic generation or administration simulation.
24-
25-
### Ghosts.Api
26-
Dotnetcore API containing both the api calls for the client (and corresponding api calls you need for integration into other systems) in one.
27-
28-
Uses postgres on the backend because there is not much that postgres can't do.
29-
30-
## LEGAL
31-
32-
[DISTRIBUTION STATEMENT A] This material has been approved for public release and unlimited distribution.
1+
![GHOSTS Logo](https://github.com/cmu-sei/GHOSTS/blob/master/assets/ghosts-logo.jpg)
2+
3+
# GHOSTS NPC AUTOMATION
4+
5+
GHOSTS is a framework for highly-complex, realistic non-player character (NPC) orchestration. It essentially realistically mimics the behavior of the different types of people you might encounter on typical office or enterprise networks. The system makes it possible for cybersecurity experts to test their skills and realistically train to defend real networks with real NPC players operating on those networks doing the things we might expect them to do: Create documents, access systems, browse the web, click, run commands, and so on.
6+
7+
As a result of the system checks required for NPCs to be situationally aware, GHOSTS also does health reporting for all configured clients on a given instance.
8+
9+
## Key Links
10+
11+
* [Quick start: Installation from distribution binaries](https://github.com/cmu-sei/GHOSTS/wiki/Installation-from-distribution-binaries)
12+
13+
* [Detailed installation and configuration information](https://github.com/cmu-sei/GHOSTS/wiki)
14+
15+
* [Don't hesitate to submit issues and feature requests](https://github.com/cmu-sei/GHOSTS/issues)
16+
17+
## Platform Components
18+
19+
### Ghosts Clients (Windows & Linux)
20+
21+
GHOSTS clients simulate users on a machine doing "user-like" things. They [can be configured](https://github.com/cmu-sei/GHOSTS/wiki/Configuring-the-Windows-Client) to perform actions including:
22+
23+
* Browse the web
24+
* Create and edit office documents
25+
* Send and respond to email
26+
* Run terminal commands
27+
* Etc.
28+
29+
### Ghosts API Server
30+
31+
The API server is a RESTful web service that provides a way for clients to interact with the GHOSTS system and its clients. It can:
32+
33+
* Manage clients, add/remove them from groups, etc.
34+
* Get/manage information from clients with regards to their activity, current activities, etc.
35+
* Orchestrate new activities for particular clients to perform
36+
37+
---
38+
39+
[DISTRIBUTION STATEMENT A] This material has been approved for public release and unlimited distribution.
40+
41+
Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms.

src/Dockerfile-api

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
#multi-stage target: dev
77
#
8-
FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS dev
8+
FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS dev
99

1010
ENV ASPNETCORE_URLS=http://*:5000 \
1111
ASPNETCORE_ENVIRONMENT=DEVELOPMENT
@@ -20,14 +20,14 @@ CMD ["dotnet", "run"]
2020
#
2121
#multi-stage target: prod
2222
#
23-
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS prod
23+
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS prod
2424
ARG commit
2525
ENV COMMIT=$commit
2626
COPY --from=dev /app/dist /app
2727
WORKDIR /app
2828

29-
ENV GHOSTS_VERSION=5.0.0.0
30-
ENV GHOSTS_API_VERSION=v5
29+
ENV GHOSTS_VERSION=6.0.0.0
30+
ENV GHOSTS_API_VERSION=v6
3131
ENV ASPNETCORE_URLS=http://*:5000
3232

3333
EXPOSE 5000

src/Ghosts.Api/Controllers/ClientTimeline.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ namespace ghosts.api.Controllers
2222
public class ClientTimelineController : Controller
2323
{
2424
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
25-
private readonly IMachineTimelineService _service;
25+
private readonly IMachineTimelinesService _service;
2626
private readonly IMachineService _machineService;
2727

28-
public ClientTimelineController(IMachineTimelineService service, IMachineService machineService)
28+
public ClientTimelineController(IMachineTimelinesService service, IMachineService machineService)
2929
{
3030
_service = service;
3131
_machineService = machineService;

src/Ghosts.Api/Controllers/ClientUpdatesController.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Ghosts.Domain;
1010
using Microsoft.AspNetCore.Http;
1111
using Microsoft.AspNetCore.Mvc;
12+
using Newtonsoft.Json.Linq;
1213
using NLog;
1314

1415
namespace Ghosts.Api.Controllers
@@ -86,6 +87,20 @@ public async Task<IActionResult> Index(CancellationToken ct)
8687

8788
await _updateService.DeleteAsync(u.Id, ct);
8889

90+
// integrators want to know that a timeline was actually delivered
91+
// (the service only guarantees that the update was received)
92+
_queue.Enqueue(
93+
new QueueEntry
94+
{
95+
Payload =
96+
new NotificationQueueEntry()
97+
{
98+
Type = NotificationQueueEntry.NotificationType.TimelineDelivered,
99+
Payload = (JObject) JToken.FromObject(update)
100+
},
101+
Type = QueueEntry.Types.Notification
102+
});
103+
89104
return Json(update);
90105
}
91106
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Ghosts.Api.Services;
6+
using Ghosts.Domain.Messages.MesssagesForServer;
7+
using Microsoft.AspNetCore.Mvc;
8+
9+
namespace ghosts.api.Controllers
10+
{
11+
public class SurveysController : Controller
12+
{
13+
private readonly ISurveyService _surveyService;
14+
15+
public SurveysController(ISurveyService surveyService)
16+
{
17+
_surveyService = surveyService;
18+
}
19+
20+
[ProducesResponseType(typeof(Survey), 200)]
21+
[HttpGet("surveys/{machineId}")]
22+
public async Task<IActionResult> Survey([FromRoute] Guid machineId, CancellationToken ct)
23+
{
24+
return Ok(await _surveyService.GetLatestAsync(machineId, ct));
25+
}
26+
27+
[ProducesResponseType(typeof(IEnumerable<Survey>), 200)]
28+
[HttpGet("surveys/{machineId}/all")]
29+
public async Task<IActionResult> SurveyAll([FromRoute] Guid machineId, CancellationToken ct)
30+
{
31+
return Ok(await _surveyService.GetAllAsync(machineId, ct));
32+
}
33+
}
34+
}

src/Ghosts.Api/Controllers/TimelineController.cs renamed to src/Ghosts.Api/Controllers/TimelinesController.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,57 @@
11
// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms.
22

33
using System;
4-
using System.Net;
54
using System.Threading;
65
using System.Threading.Tasks;
76
using Ghosts.Api.Models;
87
using Ghosts.Api.Services;
98
using Ghosts.Api.ViewModels;
109
using Microsoft.AspNetCore.Mvc;
11-
using Newtonsoft.Json;
1210
using Swashbuckle.AspNetCore.Annotations;
1311

1412
namespace ghosts.api.Controllers
1513
{
1614
/// <summary>
1715
/// Get or update a machine timeline via the API
1816
/// </summary>
19-
public class TimelineController : Controller
17+
public class TimelinesController : Controller
2018
{
2119
private readonly ITimelineService _timelineService;
22-
private readonly IMachineTimelineService _machineTimelineService;
20+
private readonly IMachineTimelinesService _machineTimelinesService;
2321

24-
public TimelineController(ITimelineService timelineService, IMachineTimelineService machineTimelineService)
22+
public TimelinesController(ITimelineService timelineService, IMachineTimelinesService machineTimelinesService)
2523
{
2624
_timelineService = timelineService;
27-
_machineTimelineService = machineTimelineService;
25+
_machineTimelinesService = machineTimelinesService;
2826
}
2927

3028
/// <summary>
31-
/// This returns the timeline for a requested machine. If the timeline is not available,
29+
/// This returns all timelines for a requested machine. If all or a specific timeline is not available,
30+
/// a MachineUpdate request can be made to retrieve the machine timelines
31+
/// </summary>
32+
/// <param name="machineId">Machine Guid</param>
33+
/// <param name="ct">Cancellation token</param>
34+
/// <returns>MachineTimelines</returns>
35+
[ProducesResponseType(typeof(MachineTimeline), 200)]
36+
[HttpGet("timelines/{machineId}")]
37+
public async Task<IActionResult> Timeline([FromRoute] Guid machineId, CancellationToken ct)
38+
{
39+
return Ok(await _machineTimelinesService.GetByMachineIdAsync(machineId, ct));
40+
}
41+
42+
/// <summary>
43+
/// This returns a specific timeline for a requested machine. If the timeline is not available,
3244
/// a MachineUpdate request can be made to retrieve the machine timeline
3345
/// </summary>
3446
/// <param name="machineId">Machine Guid</param>
47+
/// /// <param name="timelineId">Timeline Id Guid</param>
3548
/// <param name="ct">Cancellation token</param>
3649
/// <returns>MachineTimeline</returns>
3750
[ProducesResponseType(typeof(MachineTimeline), 200)]
38-
[HttpGet("timeline/{machineId}")]
39-
public async Task<IActionResult> Timeline([FromRoute] Guid machineId, CancellationToken ct)
51+
[HttpGet("timelines/{machineId}/{timelineId}")]
52+
public async Task<IActionResult> TimelineById([FromRoute] Guid machineId, [FromRoute] Guid timelineId, CancellationToken ct)
4053
{
41-
return Ok(await _machineTimelineService.GetByMachineIdAsync(machineId, ct));
54+
return Ok(await _machineTimelinesService.GetByMachineIdAndTimelineIdAsync(machineId, timelineId, ct));
4255
}
4356

4457
/// <summary>
@@ -47,14 +60,22 @@ public async Task<IActionResult> Timeline([FromRoute] Guid machineId, Cancellati
4760
/// <param name="machineUpdate">The update to send</param>
4861
/// <param name="ct">Cancellation token</param>
4962
/// <returns>204 No content</returns>
50-
[HttpPost("timeline")]
63+
[HttpPost("timelines")]
5164
// [ProducesResponseType(typeof(Task<IActionResult>), (int) HttpStatusCode.NoContent)] Swagger hates this https://stackoverflow.com/questions/35605427/swagger-ui-freezes-after-api-fetch-and-browser-crashes
5265
[SwaggerOperation(OperationId = "createTimeline")]
5366
public async Task<IActionResult> Timeline([FromBody] MachineUpdateViewModel machineUpdate, CancellationToken ct)
5467
{
5568
await _timelineService.UpdateAsync(machineUpdate, ct);
5669
return NoContent();
5770
}
71+
72+
[HttpPost("timelines/{machineId}/{timelineId}/stop")]
73+
[SwaggerOperation(OperationId = "stopTimeline")]
74+
public async Task<IActionResult> Timeline([FromRoute] Guid machineId, [FromRoute] Guid timelineId, CancellationToken ct)
75+
{
76+
await _timelineService.StopAsync(machineId, timelineId, ct);
77+
return NoContent();
78+
}
5879

5980
/// <summary>
6081
/// Send a new timeline to an entire group of machines
@@ -63,7 +84,7 @@ public async Task<IActionResult> Timeline([FromBody] MachineUpdateViewModel mach
6384
/// <param name="machineUpdate">The update to send</param>
6485
/// <param name="ct">Cancellation token</param>
6586
/// <returns>204 No content</returns>
66-
[HttpPost("timeline/bygroup/{groupId}")]
87+
[HttpPost("timelines/bygroup/{groupId}")]
6788
// [ProducesResponseType(typeof(Task<IActionResult>), (int) HttpStatusCode.NoContent)] Swagger hates this
6889
[SwaggerOperation(OperationId = "createTimelineForGroup")]
6990
public async Task<IActionResult> GroupTimeline([FromRoute] int groupId, [FromBody] MachineUpdateViewModel machineUpdate, CancellationToken ct)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Ghosts.Api.Services;
5+
using Microsoft.AspNetCore.Mvc;
6+
7+
namespace ghosts.api.Controllers
8+
{
9+
[Produces("application/json")]
10+
[Route("api/[controller]")]
11+
[ResponseCache(Duration = 5)]
12+
public class TrackablesController : Controller
13+
{
14+
private readonly ITrackableService _service;
15+
16+
public TrackablesController(ITrackableService service)
17+
{
18+
_service = service;
19+
}
20+
21+
/// <summary>
22+
/// Gets all trackables in the system
23+
/// </summary>
24+
/// <param name="ct">Cancellation Token</param>
25+
/// <returns>List of Trackables</returns>
26+
[HttpGet]
27+
public async Task<IActionResult> GetTrackables(CancellationToken ct)
28+
{
29+
var list = await _service.GetAsync(ct);
30+
if (list == null) return NotFound();
31+
return Ok(list);
32+
}
33+
34+
[HttpGet("{id}")]
35+
public async Task<IActionResult> GetTrackableHistory([FromRoute] Guid id, CancellationToken ct)
36+
{
37+
var list = await _service.GetActivityByTrackableId(id, ct);
38+
if (list == null) return NotFound();
39+
return Ok(list);
40+
}
41+
}
42+
}

src/Ghosts.Api/Models/QueueEntries.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ public class NotificationQueueEntry
3030
public enum NotificationType
3131
{
3232
Timeline = 0,
33-
WebhookCreate = 1
33+
WebhookCreate = 1,
34+
TimelineDelivered = 10
3435
}
3536

3637
public NotificationType Type { get; set; }

src/Ghosts.Api/Models/WebHook.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ public Webhook()
2727

2828
public Webhook(WebhookViewModel model)
2929
{
30-
var id = Guid.NewGuid();
31-
if (Guid.TryParse(model.Id, out id))
30+
if (Guid.TryParse(model.Id, out var id))
3231
Id = id;
3332
Status = model.Status;
3433
Description = model.Description;

0 commit comments

Comments
 (0)