├── dsc ├── Lab │ └── filler.txt └── adlab.ps1 ├── terraform ├── keys │ └── filler.txt ├── vars.tf └── aws.tf ├── .gitignore └── README.md /dsc/Lab/filler.txt: -------------------------------------------------------------------------------- 1 | This folder will contain the MOF files you need for DSC once you execute the DSC script on your local machine 2 | -------------------------------------------------------------------------------- /terraform/keys/filler.txt: -------------------------------------------------------------------------------- 1 | This folder stores your private and public key made from AWS for terraform to set it all up for you 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | terraform/keys/* 2 | terraform/.terraform.lock.hcl 3 | terraform/.terraform/ 4 | dsc/Lab/* 5 | terraform/terraform* 6 | terraform/.terraform* 7 | -------------------------------------------------------------------------------- /terraform/vars.tf: -------------------------------------------------------------------------------- 1 | variable "PATH_TO_PUBLIC_KEY" { 2 | # Add the path to the public key you made in AWS like below 3 | # default = "./keys/terraform-key.pub" 4 | default = "YOUR_PUBLIC_KEY" 5 | } 6 | 7 | variable "PATH_TO_PRIVATE_KEY" { 8 | # Add the path to the private key you made in AWS like below 9 | # default = "./keys/terraform-key.pem" 10 | default = "YOUR_PRIVATE_KEY" 11 | } 12 | 13 | variable "VPC_CIDR" { 14 | default = "10.0.0.0/16" 15 | } 16 | 17 | variable "FIRST_SUBNET_CIDR" { 18 | default = "10.0.1.0/24" 19 | } 20 | 21 | variable "SECOND_SUBNET_CIDR" { 22 | default = "10.0.2.0/24" 23 | } 24 | 25 | variable "FIRST_DC_IP" { 26 | default = "10.0.1.100" 27 | } 28 | 29 | variable "USER_SERVER_IP" { 30 | default = "10.0.1.50" 31 | } 32 | 33 | variable "ATTACK_SERVER_IP" { 34 | default = "10.0.1.10" 35 | } 36 | 37 | variable "SECOND_DC_IP" { 38 | default = "10.0.2.100" 39 | } 40 | 41 | variable "PUBLIC_DNS" { 42 | default = "1.1.1.1" 43 | } 44 | 45 | variable "MANAGEMENT_IPS" { 46 | # Add in the public IP Address you will be hitting the cloud from, for example the public IP of your home address or VPN 47 | #default = ["1.2.3.4/32"] 48 | default = ["YOUR_PUBLIC_IP"] 49 | } 50 | 51 | variable "SSM_S3_BUCKET" { 52 | # Add in the name of your S3 bucket like the example below 53 | #default = "this-is-just-a-fake-bucket" 54 | default = "YOUR_S3_BUCKET" 55 | } 56 | 57 | data "aws_ami" "latest-windows-server" { 58 | most_recent = true 59 | owners = ["amazon"] 60 | 61 | filter { 62 | name = "name" 63 | values = ["Windows_Server-2019-English-Full-Base-*"] 64 | } 65 | } 66 | 67 | # Find Latest Debian 68 | data "aws_ami" "latest-debian" { 69 | most_recent = true 70 | owners = ["136693071363"] 71 | 72 | filter { 73 | name = "name" 74 | values = ["debian-10-amd64-*"] 75 | } 76 | 77 | filter { 78 | name = "architecture" 79 | values = ["x86_64"] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS-RedTeam-ADLab 2 | 3 | ## Summary 4 | 5 | This lab consists of 3 servers across 2 domains. It includes almost all pure AD attacks that I have exploited. The only edges in Bloodhound it doesnt yet have are LAPS and GMSA I believe. 6 | 7 | Once the setup steps are done you can just launch the lab using `terraform apply` and it will do it all for you. After applying you will need to give the lab about 35 mins. When you apply it will complete and tell you a timestamp. Take that timestamp, add 35 minutes onto it and wait that time. That will give it the time it needs to do all the setup. After 35 mins it will be good to go. 8 | 9 | My blog post giving detailed setup information is here: https://philkeeble.com/automation/windows/activedirectory/AWS-RedTeam-ADLab-Setup/ 10 | 11 | ## Attacks Covered 12 | 13 | * Kerberoasting 14 | * ASRepRoasting 15 | * Constrained Delegation (computer and user) 16 | * Unconstrained Delegation 17 | * Resource Based Constrained Delegation 18 | * Write ACL of user 19 | * Write ACL of computer 20 | * WriteDACL over domain 21 | * Write ACL of group 22 | * DnsAdmin members 23 | * Write ACL of GPO 24 | * Password in AD Attributes 25 | * Cross domain trusts 26 | * SMBSigning disabled on all machines for relay attacks 27 | * Defender uninstalled so no need to worry about AV 28 | * Multiple machines so you can practise tunneling, double hop problem, etc 29 | * All the default things like lateral movement, persistence, pass the hash, pass the ticket, golden tickets, silver tickets etc 30 | 31 | ## Machine Summary 32 | 33 | * First-DC = Domain Controller of the domain first.local (10.0.1.100) 34 | * Second-DC = Domain Controller of the domain second.local (in a trust with first) (10.0.2.100) 35 | * User-Server = Server to be the foothold on. Any domain user can RDP to this box (10.0.1.50) 36 | * Attack-Server = Debian server set up with Covenent and Impacket for you to jump in and attack from (10.0.1.10) 37 | 38 | ## Setup Notes (Detailed Info in blog linked at top of README) 39 | ``` 40 | Terraform 41 | Install terraform 42 | Install aws cli 43 | set up creds in aws cli 44 | 45 | DSC 46 | Install-module -name activedirectorydsc 47 | install-module -name networkingdsc 48 | install-module -name ComputerManagementDsc 49 | install-module -name GroupPolicyDsc 50 | With these you can use ". .\adlab.ps1" to make the MOF files 51 | 52 | S3 53 | Create an S3 bucket for your account and replace the variable in terraform/vars.tf with your bucket name 54 | 55 | Management IP 56 | Change the management IP variable in vars.tf to be your IP 57 | 58 | Keys 59 | Create an EC2 key pair, get public key from the pem with ssh-keygen -y -f /key.pem 60 | Store the file ./terraform/keys/terraform-key.pub 61 | Update the file in the vars.tf to point to that public key (which will assign it to the created EC2 instances) 62 | Can use this key pair to get the administrator default password from AWS 63 | 64 | When its launched give it like half and hour and it should set up properly 65 | ``` 66 | 67 | Debugging 68 | ``` 69 | Logs are kept here C:\Windows\System32\Configuration\ConfigurationStatus on the targets for DSC 70 | 71 | The folder is owned by trusted installer so need to change owners to read or be system 72 | ``` 73 | 74 | Linux 75 | ``` 76 | Attack server has covenant and impacket on 77 | 78 | port forward 7443 79 | cd Covenant/Covenant 80 | sudo dotnet run 81 | access in browser on localhost 82 | 83 | 84 | For impackt you can run python3 psexec.py ... etc 85 | ``` 86 | # Credits 87 | 88 | Massive credit to XPN with this project https://github.com/xpn/DemoLab. Almost all of the code I used is from this project and its blog post https://www.mdsec.co.uk/2020/04/designing-the-adversary-simulation-lab/. 89 | 90 | I have just taken that, made it less mass-spinup focused and added the vulnerabilties I would want in an AD lab. 91 | -------------------------------------------------------------------------------- /terraform/aws.tf: -------------------------------------------------------------------------------- 1 | # Basic AWS configuration which will grab our keys from the AWS CLI 2 | # If you are not using the keys in the default profile of aws cli, then change below to the profile name 3 | provider "aws" { 4 | profile = "default" 5 | region = "eu-west-2" 6 | } 7 | 8 | # Our AWS keypair 9 | resource "aws_key_pair" "terraformkey" { 10 | key_name = "${terraform.workspace}-terraform-lab" 11 | public_key = file(var.PATH_TO_PUBLIC_KEY) 12 | } 13 | 14 | # Our VPC definition, using a default IP range of 10.0.0.0/16 15 | resource "aws_vpc" "lab-vpc" { 16 | cidr_block = var.VPC_CIDR 17 | enable_dns_support = true 18 | enable_dns_hostnames = true 19 | } 20 | 21 | # Default route required for the VPC to push traffic via gateway 22 | resource "aws_route" "first-internet-route" { 23 | route_table_id = aws_vpc.lab-vpc.main_route_table_id 24 | destination_cidr_block = "0.0.0.0/0" 25 | gateway_id = aws_internet_gateway.lab-vpc-gateway.id 26 | } 27 | 28 | # Gateway which allows outbound and inbound internet access to the VPC 29 | resource "aws_internet_gateway" "lab-vpc-gateway" { 30 | vpc_id = aws_vpc.lab-vpc.id 31 | } 32 | 33 | # Create our first subnet (Defaults to 10.0.1.0/24) 34 | resource "aws_subnet" "first-vpc-subnet" { 35 | vpc_id = aws_vpc.lab-vpc.id 36 | 37 | cidr_block = var.FIRST_SUBNET_CIDR 38 | availability_zone = "eu-west-2a" 39 | 40 | tags = { 41 | Name = "First Subnet" 42 | } 43 | } 44 | 45 | # Create our second subnet (Defaults to 10.0.2.0/24) 46 | resource "aws_subnet" "second-vpc-subnet" { 47 | vpc_id = aws_vpc.lab-vpc.id 48 | 49 | cidr_block = var.SECOND_SUBNET_CIDR 50 | availability_zone = "eu-west-2a" 51 | 52 | tags = { 53 | Name = "Second Subnet" 54 | } 55 | } 56 | 57 | # Set DHCP options for delivering things like DNS servers 58 | resource "aws_vpc_dhcp_options" "first-dhcp" { 59 | domain_name = "first.local" 60 | domain_name_servers = [var.FIRST_DC_IP, var.PUBLIC_DNS] 61 | ntp_servers = [var.FIRST_DC_IP] 62 | netbios_name_servers = [var.FIRST_DC_IP] 63 | netbios_node_type = 2 64 | 65 | tags = { 66 | Name = "First DHCP" 67 | } 68 | } 69 | 70 | # Associate our DHCP configuration with our VPC 71 | resource "aws_vpc_dhcp_options_association" "first-dhcp-assoc" { 72 | vpc_id = aws_vpc.lab-vpc.id 73 | dhcp_options_id = aws_vpc_dhcp_options.first-dhcp.id 74 | } 75 | 76 | # Our first domain controller of the "first.local" domain 77 | resource "aws_instance" "first-dc" { 78 | ami = data.aws_ami.latest-windows-server.image_id 79 | instance_type = "t2.small" 80 | key_name = aws_key_pair.terraformkey.key_name 81 | associate_public_ip_address = true 82 | subnet_id = aws_subnet.first-vpc-subnet.id 83 | private_ip = var.FIRST_DC_IP 84 | iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name 85 | 86 | tags = { 87 | Workspace = "${terraform.workspace}" 88 | Name = "${terraform.workspace}-First-DC" 89 | } 90 | 91 | vpc_security_group_ids = [ 92 | aws_security_group.first-sg.id, 93 | ] 94 | } 95 | 96 | # The User server which will be main foothold 97 | resource "aws_instance" "user-server" { 98 | ami = data.aws_ami.latest-windows-server.image_id 99 | instance_type = "t2.small" 100 | key_name = aws_key_pair.terraformkey.key_name 101 | associate_public_ip_address = true 102 | subnet_id = aws_subnet.first-vpc-subnet.id 103 | private_ip = var.USER_SERVER_IP 104 | iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name 105 | 106 | tags = { 107 | Workspace = "${terraform.workspace}" 108 | Name = "${terraform.workspace}-User-Server" 109 | } 110 | 111 | vpc_security_group_ids = [ 112 | aws_security_group.first-sg.id, 113 | ] 114 | } 115 | 116 | # Our second domain controller of the "second.local" domain 117 | resource "aws_instance" "second-dc" { 118 | ami = data.aws_ami.latest-windows-server.image_id 119 | instance_type = "t2.small" 120 | key_name = aws_key_pair.terraformkey.key_name 121 | associate_public_ip_address = true 122 | subnet_id = aws_subnet.second-vpc-subnet.id 123 | private_ip = var.SECOND_DC_IP 124 | iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name 125 | 126 | tags = { 127 | Workspace = "${terraform.workspace}" 128 | Name = "${terraform.workspace}-Second-DC" 129 | } 130 | 131 | vpc_security_group_ids = [ 132 | aws_security_group.second-sg.id, 133 | ] 134 | } 135 | 136 | # The C2 teamserver 137 | resource "aws_instance" "attack-server" { 138 | ami = data.aws_ami.latest-debian.image_id 139 | instance_type = "t2.small" 140 | key_name = aws_key_pair.terraformkey.key_name 141 | associate_public_ip_address = true 142 | subnet_id = aws_subnet.first-vpc-subnet.id 143 | private_ip = var.ATTACK_SERVER_IP 144 | iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name 145 | 146 | tags = { 147 | Workspace = "${terraform.workspace}" 148 | Name = "${terraform.workspace}-Attack-Server" 149 | } 150 | 151 | vpc_security_group_ids = [ 152 | aws_security_group.first-sg.id, 153 | ] 154 | } 155 | 156 | resource "null_resource" "attack-server-setup" { 157 | connection { 158 | type = "ssh" 159 | host = aws_instance.attack-server.public_ip 160 | user = "admin" 161 | port = "22" 162 | private_key = file(var.PATH_TO_PRIVATE_KEY) 163 | agent = false 164 | } 165 | 166 | provisioner "remote-exec" { 167 | inline = [ 168 | "sudo apt update", 169 | 170 | # Install dotnet 171 | "wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb", 172 | "sudo dpkg -i packages-microsoft-prod.deb", 173 | "sudo apt-get update", 174 | "sudo apt-get install -y apt-transport-https", 175 | "sudo apt-get update", 176 | 177 | # Install Covenant Stable 178 | "sudo apt-get install -y dotnet-sdk-3.1", 179 | "sudo apt-get install -y git", 180 | "git clone --recurse-submodules https://github.com/cobbr/Covenant", 181 | 182 | # Install Covenant Dev 183 | #"sudo apt-get install -y dotnet-sdk-5.0", 184 | #"git clone -b dev --recurse-submodules https://github.com/cobbr/Covenant", 185 | 186 | # Install PoshC2 187 | #"git clone https://github.com/nettitude/PoshC2.git", 188 | #"cd PoshC2", 189 | #"sudo ./Install.sh -b master -p /home/admin/PoshC2" 190 | #"cd ../" 191 | 192 | # Install Impacket 193 | "sudo apt install -y python3-pip", 194 | "git clone https://github.com/SecureAuthCorp/impacket.git", 195 | "cd impacket", 196 | "sudo python3 -m pip install --upgrade pip", 197 | "sudo python3 -m pip install .", 198 | "cd ../" 199 | ] 200 | } 201 | } 202 | 203 | # IAM Role required to access SSM from EC2 204 | resource "aws_iam_role" "ssm_role" { 205 | name = "${terraform.workspace}_ssm_role_default" 206 | count = 1 207 | assume_role_policy = <