Repository: tothi/ad-honeypot-autodeploy
Branch: master
Commit: ec48267abddf
Files: 34
Total size: 78.7 KB
Directory structure:
gitextract_tyoks_c1/
├── README.md
├── ansible/
│ ├── dashboard.json
│ ├── gen_users.py
│ ├── graylog_config.sh
│ ├── hosts
│ ├── id.pub
│ ├── nxlog.conf
│ ├── rdp_public.sh
│ ├── requirements.txt
│ ├── setup-domain.yml
│ └── wordlist.txt
├── init-passwords.sh
├── packer/
│ ├── .ssh/
│ │ ├── id_ed25519
│ │ └── id_ed25519.pub
│ ├── answer_files/
│ │ ├── graylog/
│ │ │ ├── preseed.cfg
│ │ │ └── preseed.cfg~
│ │ ├── win10/
│ │ │ └── Autounattend.xml
│ │ ├── win2012r2/
│ │ │ └── Autounattend.xml
│ │ └── win2016/
│ │ └── Autounattend.xml
│ ├── get-virtio.sh
│ ├── graylog.json
│ ├── packer-build-all.sh
│ ├── private.json
│ ├── scripts/
│ │ ├── bootstrap.ps1
│ │ ├── graylog.sh
│ │ ├── setupcomplete.ps1
│ │ ├── shutdown.ps1
│ │ └── win2012r2-dotnet-fix.ps1
│ ├── win10.json
│ ├── win2012r2.json
│ └── win2016.json
└── terraform/
├── main.tf
├── network-dhcp-lease.xsl
└── timer-patch.xsl
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# ad-honeypot-autodeploy
Deploy a small, intentionally insecure, vulnerable Windows Domain
for RDP Honeypot fully automatically.
Runs on self-hosted virtualization using [libvirt](https://libvirt.org)
with [QEMU](https://www.qemu.org/)/[KVM](https://www.linux-kvm.org/page/Main_Page) (but it can be customized easily for cloud-based solutions).
Used for painlessly set up a small Windows Domain from scratch
automatically (without user interaction) for the purpose of RDP Honeypot
testing.
Features a Domain Controller, a Desktop Computer and a configured
Graylog server for logging the actions of the bad guys.
## Automatic deployment phases
1. [Packer](https://www.packer.io/): download the necessary install media and setup the
automated base virtual machine images unattended.
2. [Terraform](https://www.terraform.io/): provision the libvirt virtualization infrastructure
(network + virtual machines) using the packer-prepared
virtual machine images.
3. [Ansible](https://www.ansible.com/): Configure the infrastructure (DC, Desktop, Graylog)
automatically, without user interaction.
After going through the Packer+Terraform+Ansible pipeline,
the configured Windows Domain should be up and running, you could
attach the RDP service of the Desktop to the public internet, and
let's monitor the events through the Graylog.
## Features
Features of the running system are:
* a Windows Server 2016 as a Domain Controller
* a Windows 10 Desktop (version 21H2) as a Domain Computer
* a [Graylog](https://www.graylog.org/) 3.3 (Open Source edition) running as a Log Collector on [Ubuntu](https://ubuntu.com/) 18.04 LTS
* Using [VirtIO](https://wiki.libvirt.org/page/Virtio) drivers for best performance
* Enabled RDP and WinRM Services
* Populated Windows Active Directory with random users
* [Sysmon](https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon) (from [Windows Sysinternals](https://docs.microsoft.com/en-us/sysinternals/)) installed and running on Domain Computers
* [NXLog](https://nxlog.co/) Collector running a Domain Computers and forwarding logs to Graylog
* Configured Graylog GeoIP lookup table and pipeline for IP addresses (useful for showing a map of invalid RDP login attempts)
* Graylog World Map of RDP attacks
* an extra [Kali](https://www.kali.org/) VM attached to the Windows subnet for playing with attack techniques
## Host System Requirements
Virtualization needs some power of your host system:
* ~100 GB disk space for the base images and the sparse images of the guest computers.
* at least 4 x 4 GB memory for the guest machines
(may run with less than 16 GB because of overcommitment)
* installed up-to-date libvirt with QEMU/KVM (official current packages in Ubuntu 18.04 LTS should work)
* Python 3 (preferably with venv) for Ansible
Tested on Ubuntu 18.04 LTS host.
## Installation and Usage
First, clone the repo:
```
git clone https://github.com/tothi/ad-honeypot-autodeploy
cd ad-honeypot-autodeploy
```
Before starting with Packer, set up the intial passwords (watch for complexity requirements):
```
./init_passwords.sh
```
### Packer
Now build the initial images.
```
cd packer
```
Windows Server 2016 and Ubuntu installation media should be downloaded
by the Packer script. VirtIO needs to be downloaded by the attached
get-virtio.sh script:
```
./get-virtio.sh
```
Windows 10 should be downloaded manually by getting a temporary
download link and save it to the ISO folder. The download link
could be obtained from [here](https://www.microsoft.com/hu-hu/software-download/windows10ISO). Select the English (International), 64-bit version and
save the ISO to `ISO/Win10_21H2_EnglishInternational_x64.iso`.
For mapping IP locations on a World Map in Graylog, the MaxMind GeoIP
database is needed. Unfortunately due to licensing terms it cannot
be redistributed, so you have to download it manually (after registering)
from the [MaxMind site](https://www.maxmind.com). The free GeoLite2 version should work, get the
"GeoLite2 City" Database in MMDB format (download the GZIP and untar)
and put it at `resources/GeoLite2-City.mmdb`.
If you do not have Packer, get the latest version from the packer.io site
([download the pre-compiled binary](https://www.packer.io/downloads.html))
or try to [add the Hashicorp repository](https://learn.hashicorp.com/tutorials/terraform/install-cli) to your packaging system (useful for Terrafrom also).
If you are rebuilding the images, do not forget to clean up previous
builds:
```
rm -fr output_*
```
If you want to re-download the images, remove packer_cache:
```
rm -fr packer_cache
```
After these preparing steps, run the Packer builds in parallel:
```
./packer-build-all.sh
```

The images should be ready in a reasonable time (~20-30 mins depending
on your host hardware power).
### Terraform
Now the infrastructure can be deployed using Terraform.
Get Terraform (>=0.13) if you do not have it (look at the install methods
at Packer, above).
[Terraform provider for libvirt](https://github.com/dmacvicar/terraform-provider-libvirt)
should be automatically downloaded from the [Terraform Registry](https://registry.terraform.io/)
during the apply phase.
Enter Terraform folder:
```
cd ../terraform
```
Initialize the working directory (only needed for first time use):
```
terraform init
```
Build and launch the infrastructure ("apply the changes"):
```
terraform apply
```
Note, that if the user running `terraform apply` is not root, sudo privileges for running `/usr/sbin/iptables`
is needed (without password).

After a short time (~2-3 mins),
the network and virtual machines are up and running. If there are any failures, `terraform destroy` might not be enough,
manual undefining resources may be necessary.
> WARNING: You should take care of protecting your private
> network. The terraform config (main.tf) provided here just contains
> a custom firewall rule for my own testing environment
> (blocking 192.168.0.0/16 destination traffic from the
> 192.168.3.0/24 honeypot network).
Next is the configuration phase.
### Ansible
Get into the ansible folder:
```
cd ../ansible
```
Recommended installation method is installing the latest Ansible
with some required additional dependencies in a Python venv virtualized
environment:
```
python3 -m venv venv
. ./venv/bin/activate
pip3 install -r requirements.txt
```
For later use just activate the venv by
```
. ./venv/bin/activate
```
And just `deactivate` if it is not needed anymore in your
current session.
You should put an SSH public key with filename `id.pub` (use `ssh-keygen`) into the ansible
folder for accessing the Ubuntu Graylog machine with the ubuntu user
(ansible will add it to `~ubuntu/.ssh/authorized_keys`).
The `wordlist.txt` file contains some (intentionally weak) passwords
for the populated domain users which can be customized.
Run the configuration phase:
```
ansible-playbook -i hosts setup-domain.yml -v
```

After 20-25 mins everything is ready.
## The deployed system
| hostname | ip address | operating system | role |
| --------- | ------------- | ------------------------- | ------------------------- |
| dc1 | 192.168.3.100 | Windows Server 2016 | Domain Controller |
| desktop12 | 192.168.3.112 | Windows 10 (version 2004) | Domain Member Workstation |
| graylog | 192.168.3.191 | Ubuntu 18.04 LTS | Graylog Server |
| kali | 192.168.3.192 | Kali Rolling (2022.3) | Offensive Operations |
According to the libvirt network configuration (NAT), the hosts can access
the public internet (if your host system allows it).
Accessing the hosts is possible through the host system.
Practically using an SSH socks tunnel and proxychains for RDP or WinRM
access is very comfortable.
For example, if your libvirt host IP is 192.168.0.10,
create a socks tunnel listening on `localhost:5000` by
```
ssh 192.168.0.10 -D5000 -NTv
```
And access the Windows 10 desktop (using an appropriate `/etc/proxychains.conf`
configured for the :5000 tunnel):
```
proxychains xfreerdp /v:192.168.3.112 /u:administrator
```
Or, access the Graylog web interface listening on :9000 locally on
the Graylog Ubuntu server by SSH ProxyJump and custom forward tunnel:
```
ssh -J 192.168.0.10 ubuntu@192.168.3.191 -NTv -L9000:127.0.0.1:9000
```
Then open URL `http://localhost:9000` and you reach the Graylog web
interface.
For activating the RDP honeypot, just allow public access
to 192.168.3.112:3389 (for example with some port forwarding
configuration on your router and iptables rules on the host
machine; my helper script is [rdp_public.sh](ansible/rdp_public.sh))
and keep watching the Graylog. ;)
================================================
FILE: ansible/dashboard.json
================================================
{
"v": 1,
"id": "2397d589-a1fd-4ad8-b271-e72f44b4611f",
"rev": 1,
"name": "RDP Attack Dashboard",
"summary": "Monitoring Dashboard for RDP Attacks",
"description": "",
"vendor": "an0n",
"url": "",
"parameters": [],
"entities": [
{
"v": "1",
"type": {
"name": "dashboard",
"version": "2"
},
"id": "e42b37b9-3e53-4e0e-ab66-064d57feacab",
"data": {
"summary": {
"@type": "string",
"@value": "Monitor RDP Attacks"
},
"search": {
"queries": [
{
"id": "703206bc-2209-44c6-9027-148d841210ba",
"timerange": {
"type": "relative",
"range": 300
},
"query": {
"type": "elasticsearch",
"query_string": ""
},
"search_types": [
{
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4625"
},
"name": "chart",
"timerange": {
"type": "relative",
"range": 0
},
"streams": [],
"series": [
{
"type": "count",
"id": "Message Count",
"field": null
}
],
"filter": null,
"rollup": true,
"row_groups": [],
"type": "pivot",
"id": "30b34c81-72ee-411e-a9e6-8bfc6d13fdce",
"column_groups": [],
"sort": []
},
{
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4625"
},
"name": "chart",
"timerange": {
"type": "relative",
"range": 0
},
"streams": [],
"series": [
{
"type": "count",
"id": "count()",
"field": null
}
],
"filter": null,
"rollup": true,
"row_groups": [
{
"type": "values",
"field": "IpAddress_geo_city",
"limit": 15
}
],
"type": "pivot",
"id": "56cd0b71-feac-4765-9750-7fc3f20486c2",
"column_groups": [],
"sort": []
},
{
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4625"
},
"name": "chart",
"timerange": {
"type": "relative",
"range": 0
},
"streams": [],
"series": [
{
"type": "count",
"id": "count()",
"field": null
}
],
"filter": null,
"rollup": true,
"row_groups": [
{
"type": "values",
"field": "IpAddress_geo_location",
"limit": 15
}
],
"type": "pivot",
"id": "1f393b80-ef25-40d4-b04d-0d4a9d8156f1",
"column_groups": [],
"sort": []
},
{
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4624 AND LogonType: 10"
},
"name": "chart",
"timerange": {
"type": "relative",
"range": 0
},
"streams": [],
"series": [
{
"type": "count",
"id": "Message Count",
"field": null
}
],
"filter": null,
"rollup": true,
"row_groups": [],
"type": "pivot",
"id": "3963de17-64fb-4178-8aec-11b4951cbb2e",
"column_groups": [],
"sort": []
}
]
}
],
"parameters": [],
"requires": {},
"owner": "admin",
"created_at": "2020-10-05T23:20:44.620Z"
},
"created_at": "2020-10-05T22:34:45.717Z",
"requires": {},
"state": {
"703206bc-2209-44c6-9027-148d841210ba": {
"selected_fields": null,
"static_message_list_id": null,
"titles": {
"widget": {
"3c978baf-6e85-431a-b4c1-6d82c3ddddc4": "RDP Attack Origin World Map",
"4db2a07e-8b77-4716-b659-029e2750dbf8": "Failed Login Attempts",
"c1e773ab-706a-4935-9c9c-7e23c02e6820": "RDP Attack Origin",
"496f078b-9707-47c2-8829-094b35d61004": "Successful RDP Logins"
}
},
"widgets": [
{
"id": "3c978baf-6e85-431a-b4c1-6d82c3ddddc4",
"type": "aggregation",
"filter": null,
"timerange": {
"type": "relative",
"range": 0
},
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4625"
},
"streams": [],
"config": {
"visualization": "map",
"event_annotation": false,
"row_pivots": [
{
"field": "IpAddress_geo_location",
"type": "values",
"config": {
"limit": 15
}
}
],
"series": [
{
"config": {
"name": null
},
"function": "count()"
}
],
"rollup": true,
"column_pivots": [],
"visualization_config": {
"viewport": {
"zoom": 1,
"center_x": 51.83577752045248,
"center_y": 23.203125000000004
}
},
"formatting_settings": null,
"sort": []
}
},
{
"id": "4db2a07e-8b77-4716-b659-029e2750dbf8",
"type": "aggregation",
"filter": null,
"timerange": {
"type": "relative",
"range": 0
},
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4625"
},
"streams": [],
"config": {
"visualization": "numeric",
"event_annotation": false,
"row_pivots": [],
"series": [
{
"config": {
"name": "Message Count"
},
"function": "count()"
}
],
"rollup": true,
"column_pivots": [],
"visualization_config": null,
"formatting_settings": null,
"sort": []
}
},
{
"id": "496f078b-9707-47c2-8829-094b35d61004",
"type": "aggregation",
"filter": null,
"timerange": {
"type": "relative",
"range": 0
},
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4624 AND LogonType: 10"
},
"streams": [],
"config": {
"visualization": "numeric",
"event_annotation": false,
"row_pivots": [],
"series": [
{
"config": {
"name": "Message Count"
},
"function": "count()"
}
],
"rollup": true,
"column_pivots": [],
"visualization_config": null,
"formatting_settings": null,
"sort": []
}
},
{
"id": "c1e773ab-706a-4935-9c9c-7e23c02e6820",
"type": "aggregation",
"filter": null,
"timerange": {
"type": "relative",
"range": 0
},
"query": {
"type": "elasticsearch",
"query_string": "EventID: 4625"
},
"streams": [],
"config": {
"visualization": "table",
"event_annotation": false,
"row_pivots": [
{
"field": "IpAddress_geo_city",
"type": "values",
"config": {
"limit": 15
}
}
],
"series": [
{
"config": {
"name": null
},
"function": "count()"
}
],
"rollup": true,
"column_pivots": [],
"visualization_config": null,
"formatting_settings": null,
"sort": []
}
}
],
"widget_mapping": {
"4db2a07e-8b77-4716-b659-029e2750dbf8": [
"30b34c81-72ee-411e-a9e6-8bfc6d13fdce"
],
"496f078b-9707-47c2-8829-094b35d61004": [
"3963de17-64fb-4178-8aec-11b4951cbb2e"
],
"c1e773ab-706a-4935-9c9c-7e23c02e6820": [
"56cd0b71-feac-4765-9750-7fc3f20486c2"
],
"3c978baf-6e85-431a-b4c1-6d82c3ddddc4": [
"1f393b80-ef25-40d4-b04d-0d4a9d8156f1"
]
},
"positions": {
"4db2a07e-8b77-4716-b659-029e2750dbf8": {
"col": 9,
"row": 1,
"height": 2,
"width": 2
},
"c1e773ab-706a-4935-9c9c-7e23c02e6820": {
"col": 7,
"row": 1,
"height": 4,
"width": 2
},
"3c978baf-6e85-431a-b4c1-6d82c3ddddc4": {
"col": 1,
"row": 1,
"height": 4,
"width": 6
},
"496f078b-9707-47c2-8829-094b35d61004": {
"col": 9,
"row": 3,
"height": 2,
"width": 2
}
},
"formatting": {
"highlighting": []
},
"display_mode_settings": {
"positions": {}
}
}
},
"properties": [],
"owner": "admin",
"title": {
"@type": "string",
"@value": "RDP Attacks"
},
"type": "DASHBOARD",
"description": {
"@type": "string",
"@value": "Basic Monitoring Dashboard"
}
},
"constraints": [
{
"type": "server-version",
"version": ">=3.3.6+92fb41e"
}
]
}
]
}
================================================
FILE: ansible/gen_users.py
================================================
#!/usr/bin/env python3
#
# generate fake users for ad:
# * importable by ansible win_domain_user module users.yml var file (slow)
# * ps1 script format (fast)
#
from faker import Factory
import random
NUM_OF_USERS = 1000
OUT_YML = "users.yml"
OUT_PS1 = "users.ps1"
OU = "Staff"
fake = Factory.create('en-GB')
group_chance = {"Domain Admins": 0.05, "RDP All": 0.8}
wordlist = list(map(lambda x: x.rstrip(), open("wordlist.txt", "r").readlines()))
def grouplist():
res = []
for g in group_chance:
if random.random() < group_chance[g]:
res.append(g)
return res
yml = open(OUT_YML, "w")
ps1 = open(OUT_PS1, "w")
ps1.write('$d = (Get-ADDomain).DistinguishedName\r\n')
ps1.write('If (Get-ADOrganizationalUnit -Filter "distinguishedName -eq \'OU={},$d\'") {{ Remove-ADOrganizationalUnit -Identity "OU={},$d" -Confirm:$False }}\r\n'.format(OU, OU))
ps1.write('New-ADOrganizationalUnit -Name "{}" -Path $d -ProtectedFromAccidentalDeletion $false\r\n'.format(OU))
yml.write("users:\n")
groupdb = {}
samdb = []
for i in range(NUM_OF_USERS):
fn = fake.first_name()
ln = fake.last_name()
pw = random.choice(wordlist)
samname_base = "{}.{}".format(fn.lower(), ln.lower())
samname = samname_base
idx = 0
while samname in samdb:
idx += 1
samname = "{}.{}".format(samname_base, idx)
samdb.append(samname)
if idx > 0:
cn = "{} {} {}".format(fn, ln, idx)
else:
cn = "{} {}".format(fn, ln)
yml.write(" - name: {}\n".format(samname))
yml.write(" firstname: {}\n".format(fn))
yml.write(" surname: {}\n".format(ln))
yml.write(" password: {}\n".format(pw))
yml.write(" state: present\n")
yml.write(" groups:\n")
ps1.write('New-ADUser -Enabled $true -AccountPassword (ConvertTo-SecureString -AsPlainText "{}" -Force) -Name "{}" -GivenName "{}" -Surname "{}" -SamAccountName "{}" -Path "OU={},$d"\r\n'.format(pw, cn, fn, ln, samname, OU))
for g in grouplist():
yml.write(" - {}\n".format(g))
if g not in groupdb:
groupdb[g] = []
groupdb[g].append(samname)
for g in groupdb:
ps1.write('If (-Not (Get-ADGroup -Filter "Name -eq \'{}\'")) {{ New-ADGroup -Name "{}" -GroupScope Global }}'.format(g, g))
ps1.write('Add-ADGroupMember -Identity "{}" -Members "{}"\r\n'.format(g, '","'.join(groupdb[g])))
yml.close()
ps1.close()
================================================
FILE: ansible/graylog_config.sh
================================================
#!/bin/bash
#
# create Graylog lookup table (using previously created adapter + caches) by API calls
#
USER="$1"
PASS="$2"
ADAPTER=`/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' http://${USER}:${PASS}@127.0.0.1:9000/api/system/lookup/adapters | /usr/bin/jq '.data_adapters[] | select(.name=="geoip")' | /usr/bin/jq -r '.id'`
CACHE=`/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' http://${USER}:${PASS}@127.0.0.1:9000/api/system/lookup/caches | /usr/bin/jq '.caches[] | select(.name=="geoip")' | /usr/bin/jq -r '.id'`
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/lookup/tables" -X POST --data "{\"title\":\"GeoIP\",\"description\":\"GeoIP Lookup Table\",\"name\":\"geoip\",\"cache_id\":\"${CACHE}\",\"data_adapter_id\":\"${ADAPTER}\",\"content_pack\":null,\"default_single_value\":\"\",\"default_single_value_type\":\"NULL\",\"default_multi_value\":\"\",\"default_multi_value_type\":\"NULL\"}}"
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/pipelines/rule" -X POST --data '{"title":"GeoIP lookup: IpAddress","description":"","source":"rule \"GeoIP lookup: IpAddress\"\nwhen\n has_field(\"IpAddress\")\nthen\nlet geo = lookup(\"geoip\", to_string($message.IpAddress));\nset_field(\"IpAddress_geo_location\", geo[\"coordinates\"]);\nset_field(\"IpAddress_geo_country\", geo[\"country\"].iso_code);\nset_field(\"IpAddress_geo_city\", geo[\"city\"].names.en);\nend\n"}'
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/pipelines/pipeline" -X POST --data '{"title":"GeoIP lookup","description":"","source":"pipeline \"GeoIP lookup\"\nstage 0 match either\nrule \"GeoIP lookup: IpAddress\"\nend","stages":[{"stage":0,"match_all":false,"rules":["GeoIP lookup: IpAddress"]}]}'
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/pipelines/pipeline"
PIPELINE=`/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/pipelines/pipeline" | /usr/bin/jq '.[] | select(.title=="GeoIP lookup")' | /usr/bin/jq -r '.id'`
STREAM="000000000000000000000001"
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/pipelines/connections/to_stream" -X POST --data "{\"stream_id\":\"${STREAM}\",\"pipeline_ids\":[\"${PIPELINE}\"]}"
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/content_packs" -X POST -d @/home/ubuntu/dashboard.json
/usr/bin/curl -s -H 'Content-Type: application/json' -H 'X-Requested-By: cli' "http://${USER}:${PASS}@127.0.0.1:9000/api/system/content_packs/2397d589-a1fd-4ad8-b271-e72f44b4611f/1/installations" -X POST -d '{"parameters": {}, "comment": ""}'
================================================
FILE: ansible/hosts
================================================
[domain]
dc1 ansible_host=192.168.3.100 ansible_user=Administrator ansible_password='{{ domain_admin_password }}'
desktop12 ansible_host=192.168.3.112 ansible_user=Administrator ansible_password='{{ default_password }}'
[domain:vars]
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_port=5985
dns_name=ecorp.local
default_password=
domain_admin_password=
dsrm_password=
[monitor]
graylog ansible_host=192.168.3.191 ansible_connection=ssh ansible_user=ubuntu ansible_ssh_private_key_file=../packer/.ssh/id_ed25519
[monitor:vars]
ubuntu_password=
graylog_admin=admin
graylog_pwd=
================================================
FILE: ansible/id.pub
================================================
================================================
FILE: ansible/nxlog.conf
================================================
define ROOT C:\Program Files (x86)\nxlog
Moduledir %ROOT%\modules
Module xm_gelf
Module im_msvistalog
Path eventlog => graylog
================================================
FILE: ansible/rdp_public.sh
================================================
#!/bin/bash
#
help () {
echo "$0 [on/off]"
}
if [ $# -ne 1 ]; then
help
exit 0
fi
if [ "$1" == "on" ]; then
iptables -I FORWARD -p tcp -d 192.168.3.112 --dport 3389 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A PREROUTING -p tcp -i br0 --dport 14999 -j DNAT --to-destination 192.168.3.112:3389
echo "Public RDP access enabled"
exit 0
elif [ "$1" == "off" ]; then
iptables -D FORWARD -p tcp -d 192.168.3.112 --dport 3389 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -D PREROUTING -p tcp -i br0 --dport 14999 -j DNAT --to-destination 192.168.3.112:3389
echo "Public RDP access disabled"
exit 0
fi
help
exit 0
================================================
FILE: ansible/requirements.txt
================================================
wheel
ansible
pywinrm
faker
================================================
FILE: ansible/setup-domain.yml
================================================
- name: Configure DC1
hosts: dc1
gather_facts: false
# vars_files:
# - users.yml
tasks:
- name: Using the default admin password
set_fact: ansible_password='{{ default_password }}'
- name: Waiting for WinRM...
wait_for_connection:
- name: Install AD Features
win_feature:
name: AD-Domain-Services
include_management_tools: yes
include_sub_features: yes
state: present
register: ad_features
- name: Set Hostname
win_hostname:
name: '{{ inventory_hostname }}'
register: dc_hostname
- name: Reboot Server
win_reboot:
msg: "Installing AD. Rebooting..."
pre_reboot_delay: 15
when: ad_features.reboot_required or dc_hostname.reboot_required
- name: Install Domain
win_domain:
dns_domain_name: '{{ dns_name }}'
safe_mode_password: '{{ dsrm_password }}'
register: ad
- name: Reboot Server
win_reboot:
msg: "Installing AD. Rebooting..."
pre_reboot_delay: 15
when: ad.reboot_required
- name: Waiting for Active Directory Web Services...
win_wait_for:
port: 9389
- name: Weaken Security Policy
win_shell: Set-ADDefaultDomainPasswordPolicy -Identity {{ dns_name }} -ComplexityEnabled 0 -LockoutThreshold 0
retries: 10
delay: 30
register: result
until: result.rc == 0
- name: Change Administrator password in domain
win_domain_user:
name: Administrator
state: present
password: '{{ domain_admin_password }}'
- name: Using the new domain Administrator password
set_fact: ansible_password='{{ domain_admin_password }}'
- name: Generate ADUser PS script
command: ./gen_users.py
delegate_to: 127.0.0.1
- name: Populate domain users
script: users.ps1
# - name: Populate domain users
# win_domain_user:
# name: '{{ item.name }}'
# state: present
# password: '{{ item.password }}'
# groups: '{{ item.groups }}'
# with_items: '{{ users }}'
# async: 600
# poll: 0
# register: create_users
#
# - name: Check users
# async_status:
# jid: "{{ create_users.ansible_job_id }}"
# register: job_result
# until: job_result.finished
# retries: 30
- name: Configure Graylog
hosts: graylog
gather_facts: false
tasks:
- name: Write new host keys to known hosts
shell: '/usr/bin/ssh-keygen -R {{ ansible_host }}; /usr/bin/ssh-keyscan -H {{ ansible_host }} | /bin/grep -v "^#" >> ~/.ssh/known_hosts'
delegate_to: 127.0.0.1
- name: Configure GELF UDP Collection
uri:
url: http://127.0.0.1:9000/api/system/inputs
method: POST
user: "{{ graylog_admin }}"
password: "{{ graylog_pwd }}"
body: '{"title":"nxlog_udp","type":"org.graylog2.inputs.gelf.udp.GELFUDPInput","configuration":{"bind_address":"0.0.0.0","port":12201,"recv_buffer_size":262144,"override_source":null,"decompress_size_limit":8388608},"global":true}'
force_basic_auth: yes
status_code: 201
body_format: json
headers:
X-Requested-By: cli
- name: Add Graylog Adapter for GeoIP Lookup
uri:
url: http://127.0.0.1:9000/api/system/lookup/adapters
method: POST
user: "{{ graylog_admin }}"
password: "{{ graylog_pwd }}"
body: '{"title":"GeoIP","description":"GeoIP Adapter","name":"geoip","custom_error_ttl_enabled":false,"custom_error_ttl":null,"custom_error_ttl_unit":null,"content_pack":null,"config":{"type":"maxmind_geoip","type":"maxmind_geoip","path":"/etc/graylog/server/GeoLite2-City.mmdb","database_type":"MAXMIND_CITY","check_interval":1,"check_interval_unit":"HOURS"}}'
force_basic_auth: yes
status_code: 200
body_format: json
headers:
X-Requested-By: cli
- name: Add Graylog Cache for GeoIP Lookup
uri:
url: http://127.0.0.1:9000/api/system/lookup/caches
method: POST
user: "{{ graylog_admin }}"
password: "{{ graylog_pwd }}"
body: '{"config":{"type":"guava_cache","type":"guava_cache","max_size":1000,"expire_after_access":1,"expire_after_access_unit":"HOURS","expire_after_write":0,"expire_after_write_unit":null},"title":"GeoIP","description":"GeoIP Cache","name":"geoip","content_pack":null}'
force_basic_auth: yes
status_code: 200
body_format: json
headers:
X-Requested-By: cli
- name: Copy dashboard.json
copy:
src: dashboard.json
dest: '/home/ubuntu/dashboard.json'
- name: More Configuration for Graylog...
script: graylog_config.sh '{{ graylog_admin }}' '{{ graylog_pwd }}'
- name: Disable SSH Password Auth
shell: "echo {{ ubuntu_password }} | /usr/bin/sudo -S /bin/sh -c '/bin/sed -i \"/PasswordAuthentication/cPasswordAuthentication no\" -i /etc/ssh/sshd_config; /bin/systemctl reload sshd'"
- name: Add extra SSH key
lineinfile:
path: /home/ubuntu/.ssh/authorized_keys
insertafter: EOF
line: "{{ lookup('file', 'id.pub') }}"
- name: Join Desktops
hosts: domain
gather_facts: true
tasks:
- name: Sync NTP Time
win_command: w32tm /resync
- name: Join Desktops
win_domain_membership:
dns_domain_name: '{{ dns_name }}'
hostname: '{{ inventory_hostname }}'
domain_admin_user: Administrator@{{dns_name}}
domain_admin_password: '{{ domain_admin_password }}'
state: domain
register: domain_state
- name: Reboot Server
win_reboot:
msg: 'Joined Domain. Rebooting...'
when: domain_state.reboot_required
- name: Install Softwares on Domain
hosts: domain
gather_facts: false
tasks:
- name: Install Firefox
win_chocolatey:
name: firefox
state: present
- name: Install NXLog Collector
win_chocolatey:
name: nxlog
state: present
- name: Install Sysmon
win_chocolatey:
name: sysmon
ignore_checksums: true
state: present
- name: Configure Logging
hosts: domain
gather_facts: false
tasks:
- name: Configure NXLog
win_copy:
src: nxlog.conf
dest: 'c:\Program Files (x86)\nxlog\conf\nxlog.conf'
- name: Fetch Sysmon config
win_get_url:
url: https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml
dest: 'c:\windows\sysmonconfig-export.xml'
- name: Launch Sysmon Service
win_command: 'c:\ProgramData\chocolatey\bin\Sysmon64.exe -accepteula -i c:\windows\sysmonconfig-export.xml'
- name: Restart NXLog
win_service:
name: nxlog
state: restarted
================================================
FILE: ansible/wordlist.txt
================================================
Summer2020
Spring2020
Spring2019
Winter2019
Autumn2019
Password123
================================================
FILE: init-passwords.sh
================================================
#!/bin/bash
#
echo "[*] Setting initial passwords."
echo -n "[?] Enter default Windows local Administrator password: "
read -s adminpass
echo
echo -n "[?] Enter Windows Domain Admin password for user ECORP\\Administrator: "
read -s domainadminpass
echo
echo -n "[?] Enter DSRM password for Windows Domain: "
read -s dsrmpass
echo
echo -n "[?] Enter password for sudo user 'ubuntu' on Ubuntu (Graylog) system: "
read -s ubuntupass
echo
echo -n "[?] Enter Graylog password for root user 'admin': "
read -s graylogpass
echo
echo -n "[?] Enter password for sudo user 'kali' on Kali system: "
read -s kalipass
echo
echo "[*] Setting Windows local Administrator password, Ubuntu user password and Kali password in packer/private.json"
adminpass_esc=$(printf '%s\n' "${adminpass}" | sed -e 's/[\/&]/\\&/g')
ubuntupass_esc=$(printf '%s\n' "${ubuntupass}" | sed -e 's/[\/&]/\\&/g')
kalipass_esc=$(printf '%s\n' "${kalipass}" | sed -e 's/[\/&]/\\&/g')
sed -i packer/private.json -e "s/\"administrator_password\": \".*\"/\"administrator_password\": \"${adminpass_esc}\"/" \
-e "s/\"ubuntu_password\": \".*\"/\"ubuntu_password\": \"${ubuntupass_esc}\"/" \
-e "s/\"kali_password\": \".*\"/\"kali_password\": \"${kalipass_esc}\"/"
p1=`echo -n "${adminpass}Password" | iconv -tutf-16le | base64 -w0`
p2=`echo -n "${adminpass}AdministratorPassword" | iconv -tutf-16le | base64 -w0`
for w in win2016 win10 win2012r2; do
a="packer/answer_files/${w}/Autounattend.xml"
echo "[*] Setting Windows local Administrator password in ${a} for UserAccounts and AutoLogon"
sed -i "$a" -e "//,/<\/Password>/ s/.*<\/Value>/${p1}<\/Value>/" \
-e "//,/<\/AdministratorPassword>/ s/.*<\/Value>/${p2}<\/Value>/"
done
echo "[*] Creating SSH key for Ubuntu (Graylog) and Kali access..."
rm -fr packer/.ssh
mkdir packer/.ssh
ssh-keygen -t ed25519 -f packer/.ssh/id_ed25519 -N "" -C supervisor@infra
SSH_PUBKEY=`cat packer/.ssh/id_ed25519.pub | tr -d '\n'`
echo "[*] Setting Ubuntu password and SSH key in packer/answer_files/graylog/preseed.cfg"
ubuntupasscrypt=`mkpasswd -m sha-512 -S $(pwgen -ns 16 1) ${ubuntupass}`
sed -i packer/answer_files/graylog/preseed.cfg -e "s#d-i passwd/user-password-crypted password .*#d-i passwd/user-password-crypted password ${ubuntupasscrypt}#" \
-e "s#echo ssh-ed25519 AAA.* supervisor@infra#echo ${SSH_PUBKEY}#"
echo "[*] Setting Graylog password in packer/scripts/graylog.sh"
graylogsha2=`echo -n "${graylogpass}" | sha256sum | cut -d' ' -f1`
sed -i packer/scripts/graylog.sh -e "s/GRAYLOG_SHA2=\".*\"/GRAYLOG_SHA2=\"${graylogsha2}\"/"
echo "[*] Setting Kali password and SSH key in packer/answer_files/kali/preseed.cfg"
kalipasscrypt=`mkpasswd -m sha-512 -S $(pwgen -ns 16 1) ${kalipass}`
sed -i packer/answer_files/kali/preseed.cfg -e "s#d-i passwd/user-password-crypted password .*#d-i passwd/user-password-crypted password ${kalipasscrypt}#" \
-e "s#echo ssh-ed25519 AAA.* supervisor@infra#echo ${SSH_PUBKEY}#"
echo "[*] Updating passwords in ansible/hosts"
domainadminpass_esc=$(printf '%s\n' "${domainadminpass}" | sed -e 's/[\/&]/\\&/g')
dsrmpass_esc=$(printf '%s\n' "${dsrmpass}" | sed -e 's/[\/&]/\\&/g')
graylogpass_esc=$(printf '%s\n' "${graylogpass}" | sed -e 's/[\/&]/\\&/g')
sed -i ansible/hosts -e "s/^default_password=.*/default_password=\"${adminpass_esc}\"/" \
-e "s/^domain_admin_password=.*/domain_admin_password=\"${domainadminpass_esc}\"/" \
-e "s/^dsrm_password=.*/dsrm_password=\"${dsrmpass_esc}\"/" \
-e "s/^ubuntu_password=.*/ubuntu_password=\"${ubuntupass_esc}\"/" \
-e "s/^graylog_pwd=.*/graylog_pwd=\"${graylogpass_esc}\"/"
echo "[+] Done. Deploy with packer+terraform+ansible."
================================================
FILE: packer/.ssh/id_ed25519
================================================
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCGBoPvk7BWDdlq9umPbz3LbaDEV8egoPlg++gzywglxwAAAJhCYCqIQmAq
iAAAAAtzc2gtZWQyNTUxOQAAACCGBoPvk7BWDdlq9umPbz3LbaDEV8egoPlg++gzywglxw
AAAEA7owk2wVvt21vApPlle6zQ8IaQpi/LiTh2aab5jFiwh4YGg++TsFYN2Wr26Y9vPctt
oMRXx6Cg+WD76DPLCCXHAAAAEnVidW50dUBwYWNrZXItaG9zdAECAw==
-----END OPENSSH PRIVATE KEY-----
================================================
FILE: packer/.ssh/id_ed25519.pub
================================================
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIYGg++TsFYN2Wr26Y9vPcttoMRXx6Cg+WD76DPLCCXH ubuntu@packer-host
================================================
FILE: packer/answer_files/graylog/preseed.cfg
================================================
#d-i debconf/priority string critical
#d-i auto-install/enable boolean true
# localization
d-i debian-installer/locale string en_US
# keyboard
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/xkb-keymap select us
# use dhcp network configuration
d-i netcfg/choose_interface select auto
# user setup
d-i passwd/user-fullname string ubuntu
d-i passwd/username string ubuntu
# mkpasswd -m sha-512 -S $(pwgen -ns 16 1) mypassword
d-i passwd/user-password-crypted password $6$r7ItP8TFvsgaLKsa$MvlIgvX/wpjITq/74dPLebOfoS9CoEA9NWuFPKfVonmZKiPQGYI6f6wflHPgOEBGGRAHRDd9vDM7Ox9TbPrOh1
# clock & timezone
d-i clock-setup/utc boolean true
d-i time/zone string Europe/Budapest
# auto-partition, all files in one partition
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
d-i partman/choose_partition select finish
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm boolean true
# packages
d-i pkgsel/include string openssh-server
d-i pkgsel/upgrade select full-upgrade
d-i pkgsel/update-policy select none
# reboot at the end
d-i finish-install/reboot_in_progress note
d-i preseed/late_command string \
in-target sh -c "mkdir -m 700 /home/ubuntu/.ssh ; echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIYGg++TsFYN2Wr26Y9vPcttoMRXx6Cg+WD76DPLCCXH ubuntu@packer-host > /home/ubuntu/.ssh/authorized_keys; chmod 600 /home/ubuntu/.ssh/authorized_keys; chown -R ubuntu:ubuntu /home/ubuntu/.ssh"
================================================
FILE: packer/answer_files/graylog/preseed.cfg~
================================================
#d-i debconf/priority string critical
#d-i auto-install/enable boolean true
# localization
d-i debian-installer/locale string en_US
# keyboard
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/xkb-keymap select us
# use dhcp network configuration
d-i netcfg/choose_interface select auto
# user setup
d-i passwd/user-fullname string ubuntu
d-i passwd/username string ubuntu
# mkpasswd -m sha-512 -S $(pwgen -ns 16 1) mypassword
d-i passwd/user-password-crypted password $6$WwICQQbv2lPNRZLh$4oivwzgiU/ydX4NcljluqtJfRKmJO.ktaj/fDCiv.bcqzxeQiEfDwcK8mKMteNHKzYtapG6znOhNTFpDIeuFI.
# clock & timezone
d-i clock-setup/utc boolean true
d-i time/zone string Europe/Budapest
# auto-partition, all files in one partition
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
d-i partman/choose_partition select finish
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm boolean true
# packages
d-i pkgsel/include string openssh-server
d-i pkgsel/upgrade select full-upgrade
d-i pkgsel/update-policy select none
# reboot at the end
d-i finish-install/reboot_in_progress note
d-i preseed/late_command string \
in-target sh -c "mkdir -m 700 /home/ubuntu/.ssh ; echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMR2FQi9N1SCsnrwpAuyiGo4e/rpZ665q28wu3QPvXBh istvan@archive01-host > /home/ubuntu/.ssh/authorized_keys; chmod 600 /home/ubuntu/.ssh/authorized_keys; chown -R ubuntu:ubuntu /home/ubuntu/.ssh"
================================================
FILE: packer/answer_files/win10/Autounattend.xml
================================================
en-US
0409:00000409
en-GB
en-GB
en-GB
a:\
1
350
Primary
2
true
Primary
true
false
NTFS
1
1
false
false
NTFS
C
2
2
0
true
/IMAGE/NAME
Windows 10 Pro
0
2
false
OnError
VK7JG-NPHTM-C97JM-9MPGT-3V66T
OnError
true
UABhAHMAcwB3AG8AcgBkAA==
false
true
1
administrator
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 0 /f
Disable AutoLogon (LogonCount issue fix)
1
2
Bootstrap Script
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass a:\bootstrap.ps1
true
true
true
true
true
3
QQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgBQAGEAcwBzAHcAbwByAGQA
false
Central Europe Standard Time
0409:00000409
en-GB
en-GB
en-GB
================================================
FILE: packer/answer_files/win2012r2/Autounattend.xml
================================================
1
350
Primary
true
2
Primary
true
false
NTFS
1
1
false
false
NTFS
C
2
2
0
true
/IMAGE/NAME
Windows Server 2012 R2 SERVERSTANDARD
0
2
false
OnError
OnError
true
en-US
en-US
en-US
en-US
en-US
a:\
QQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgBQAGEAcwBzAHcAbwByAGQA
false
UABhAHMAcwB3AG8AcgBkAA==
false
true
administrator
1
2
Bootstrap Script
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass a:\bootstrap.ps1
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 0 /f
Disable AutoLogon (LogonCount issue fix)
1
Central Europe Standard Time
================================================
FILE: packer/answer_files/win2016/Autounattend.xml
================================================
en-US
en-US
en-US
en-US
en-US
a:\
1
350
Primary
2
true
Primary
true
1
1
NTFS
false
false
false
NTFS
C
2
2
0
true
/IMAGE/NAME
Windows Server 2016 SERVERSTANDARD
0
2
false
OnError
OnError
true
UABhAHMAcwB3AG8AcgBkAA==
false
true
1
administrator
1
Disable AutoLogon (LogonCount issue fix)
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 0 /f
2
Bootstrap Script
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass a:\bootstrap.ps1
QQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgBQAGEAcwBzAHcAbwByAGQA
false
Central Europe Standard Time
================================================
FILE: packer/get-virtio.sh
================================================
#!/bin/bash
#
echo "[*] Cleaning up & init virtio folder..."
rm -fr virtio
mkdir virtio
if ! cd virtio; then
echo "[!] Problem creating virtio folder"
exit 0
fi
echo "[*] Downloading stable virtio-win.iso..."
wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
echo "[*] Extracting iso..."
mkdir virtio-win
7z x -ovirtio-win virtio-win.iso
echo "[*] Arranging drivers..."
shopt -s nullglob
for winver in w10 w8.1 2k16; do
mkdir -p ${winver}/core
mkdir -p ${winver}/extra
for driver in NetKVM viostor; do
for f in virtio-win/${driver}/${winver}/amd64/*.{inf,cat,sys,dll}; do
mv $f ${winver}/core
done
done
for driver in Balloon viorng vioserial qxldod; do
for f in virtio-win/${driver}/${winver}/amd64/*.{inf,cat,sys,dll}; do
mv $f ${winver}/extra
done
done
done
shopt -u nullglob
echo "[*] Cleaning up..."
rm -fr virtio-win
================================================
FILE: packer/graylog.json
================================================
{
"builders": [
{
"type": "qemu",
"name": "qemu-graylog",
"iso_url": "http://cdimage.ubuntu.com/releases/18.04/release/ubuntu-18.04.6-server-amd64.iso",
"iso_checksum": "sha256:f5cbb8104348f0097a8e513b10173a07dbc6684595e331cb06f93f385d0aecf6",
"output_directory": "output_graylog",
"disk_size": "20480M",
"format": "qcow2",
"accelerator": "kvm",
"cpus": "2",
"memory": "4096",
"vm_name": "graylog",
"net_device": "virtio-net",
"disk_interface": "virtio",
"http_directory": "answer_files/graylog",
"communicator": "ssh",
"ssh_username": "ubuntu",
"ssh_private_key_file": ".ssh/id_ed25519",
"ssh_timeout": "20m",
"headless": true,
"boot_wait": "10s",
"boot_command": [
"", "", "",
"/install/vmlinuz", " initrd=/install/initrd.gz",
" auto-install/enable=true",
" debconf/priority=critical",
" preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg",
" -- ",
""
],
"shutdown_command": "echo '{{user `ubuntu_password`}}' | sudo -S shutdown -P now"
}
],
"provisioners": [
{
"type": "file",
"source": "resources/GeoLite2-City.mmdb",
"destination": "GeoLite2-City.mmdb"
},
{
"type": "shell",
"script": "scripts/graylog.sh",
"execute_command": "echo '{{user `ubuntu_password`}}' | sudo -S bash {{.Path}}"
}
]
}
================================================
FILE: packer/packer-build-all.sh
================================================
#!/bin/bash
#
echo "[*] Running packers..."
packer build -timestamp-ui -var-file private.json win2016.json &
packer build -timestamp-ui -var-file private.json win10.json &
packer build -timestamp-ui -var-file private.json graylog.json &
packer build -timestamp-ui -var-file private.json kali.json &
wait
echo "[+] All of the builds have been completed."
================================================
FILE: packer/private.json
================================================
{
"administrator_password": "",
"ubuntu_password": "",
"kali_password": ""
}
================================================
FILE: packer/scripts/bootstrap.ps1
================================================
# bootstrap script for win2012r2 and win2016 packer image
New-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff" -Force
Write-Output "[*] New Network Window Popup -> OFF"
$ifaceinfo = Get-NetConnectionProfile
Set-NetConnectionProfile -InterfaceIndex $ifaceinfo.InterfaceIndex -NetworkCategory Private
Write-Output "[*] NetConnectionProfile -> Private"
Set-WSManQuickConfig -Force
Set-Item WSMan:\localhost\Service\AllowUnencrypted $true
Write-Output "[!] INSECURE!!! WARNING!!! AllowUnencrypted WSMan over HTTP"
================================================
FILE: packer/scripts/graylog.sh
================================================
#!/bin/bash
#
echo "=== Setup Graylog ==="
GRAYLOG_TIMEZONE="Europe/Budapest"
GRAYLOG_SHA2="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" # Gr@yl0g_Rul3z
DEBIAN_FRONTEND=noninteractive
echo "[*] Upgrade base"
apt-get install -y software-properties-common
add-apt-repository universe
apt-get update && apt-get upgrade
apt-get install -y apt-transport-https openjdk-8-jre-headless uuid-runtime pwgen gnupg libterm-readline-gnu-perl curl jq
echo "[*] Installing MongoDB"
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.0.list
apt-get update
apt-get install -y mongodb-org
echo "[*] Enabling mongodb"
systemctl daemon-reload
systemctl enable mongod.service
systemctl restart mongod.service
systemctl --type=service --state=active | grep mongod
echo "[*] Installing Elasticsearch"
wget -q https://artifacts.elastic.co/GPG-KEY-elasticsearch -O myKey
apt-key add myKey
rm myKey
echo "deb https://artifacts.elastic.co/packages/oss-6.x/apt stable main" | tee -a /etc/apt/sources.list.d/elastic-6.x.list
apt-get update && apt-get install -y elasticsearch-oss
echo "[*] Configuring Elasticsearch"
sed -i /etc/elasticsearch/elasticsearch.yml \
-e '/cluster\.name:/c\cluster.name: graylog' \
-e '$ a action.auto_create_index: false'
echo "[*] Enabling Elasticsearch"
systemctl daemon-reload
systemctl enable elasticsearch.service
systemctl restart elasticsearch.service
systemctl --type=service --state=active | grep elasticsearch
echo "[*] Installing Graylog"
wget https://packages.graylog2.org/repo/packages/graylog-3.3-repository_latest.deb
dpkg -i graylog-3.3-repository_latest.deb
rm graylog-3.3-repository_latest.deb
apt-get update && apt-get install -y graylog-server graylog-enterprise-plugins graylog-integrations-plugins graylog-enterprise-integrations-plugins
echo "[*] Installing Slack plugin"
wget https://github.com/graylog-labs/graylog-plugin-slack/releases/download/3.1.0/graylog-plugin-slack-3.1.0.deb
dpkg -i graylog-plugin-slack-3.1.0.deb
rm graylog-plugin-slack-3.1.0.deb
echo "[*] Configuring Graylog"
SECRET=`pwgen -N 1 -s 96`
sed -i /etc/graylog/server/server.conf \
-e "/^password_secret/c\\password_secret = ${SECRET}" \
-e "/^root_password_sha2/c\\root_password_sha2 = ${GRAYLOG_SHA2}" \
-e "/root_timezone/c\\root_timezone = ${GRAYLOG_TIMEZONE}"
echo "[*] Enabling Graylog"
systemctl daemon-reload
systemctl enable graylog-server.service
systemctl start graylog-server.service
systemctl --type=service --state=active | grep graylog
echo "[*] Copying GeoLite2-City.mmdb to /etc/graylog/server/"
cp ~ubuntu/GeoLite2-City.mmdb /etc/graylog/server/
echo "=== Setup Graylog Done ==="
================================================
FILE: packer/scripts/setupcomplete.ps1
================================================
Write-Output "[*] Installing extra VirtIO drivers..."
<# this was fixed in new VirtIO release, no need to install custom cert
$driverFile = "c:\windows\temp\extra\balloon.sys"
$certFile = "c:\windows\temp\extra\redhat.cer"
$exportType = [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert
$cert = (Get-AuthenticodeSignature $driverFile).SignerCertificate;
[System.IO.File]::WriteAllBytes($certFile, $cert.Export($exportType));
Import-Certificate -FilePath $certFile -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
#>
pnputil -i -a c:\windows\temp\extra\balloon.inf
pnputil -i -a c:\windows\temp\extra\qxldod.inf
pnputil -i -a c:\windows\temp\extra\viorng.inf
pnputil -i -a c:\windows\temp\extra\vioser.inf
Write-Output "[*] Disabling Auto-Hibernate..."
powercfg -hibernate OFF
Write-Output "[*] Enabling Windows Time Service"
Set-Service -Name w32time -StartupType Automatic
sc.exe triggerinfo w32time delete
Write-Output "[*] Checking for Windows 10..."
If ([Environment]::OSVersion.Version -ge (new-object 'Version' 10,0)) {
Write-Output "[+] Validated Windows 10"
Write-Output "[*] Disabling Windows AutoUpdate"
New-Item HKLM:\SOFTWARE\Policies\Microsoft\Windows -Name WindowsUpdate
New-Item HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate -Name AU
New-ItemProperty HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU -Name NoAutoUpdate -Value 1
Write-Output "[*] Disabling Windows Defender"
Set-MpPreference -DisableIntrusionPreventionSystem $true `
-DisableIOAVProtection $true `
-DisableRealtimeMonitoring $true `
-DisableScriptScanning $true `
-EnableControlledFolderAccess Disabled `
-EnableNetworkProtection AuditMode `
-Force -MAPSReporting Disabled `
-SubmitSamplesConsent NeverSend
} Else {
Write-Output "[!] Older Windows detected"
}
Write-Output "[*] Allowing incoming WinRM on Any Profile in Firewall..."
New-NetFirewallRule -DisplayName "Allow WinRM" -Direction Inbound -LocalPort 5985 -Protocol TCP -Action Allow -Profile Any
Write-Output "[*] Enabling RDP..."
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
Write-Output "[+] Setup complete. Cleaning up files..."
Remove-Item -Recurse -Force -Path c:/windows/temp/extra
================================================
FILE: packer/scripts/shutdown.ps1
================================================
Set-Item WSMan:\localhost\Service\AllowUnencrypted $false
Write-Output "[+] Disabled Unencrypted WSMan over HTTP"
shutdown /s /t 5 /f /d p:4:1 /c "Packer Shutdown"
================================================
FILE: packer/scripts/win2012r2-dotnet-fix.ps1
================================================
Write-Host "[*] Fixing CPU spiking caused by .NET Runtime Optimization Service"
Get-ChildItem $env:SystemRoot/Microsoft.net/NGen.exe -recurse | %{ & $_ executeQueuedItems }
================================================
FILE: packer/win10.json
================================================
{
"builders": [
{
"type": "qemu",
"name": "qemu-win10",
"iso_url": "ISO/Win10_21H2_EnglishInternational_x64.iso",
"iso_checksum": "sha256:06fd4a512c5f3e8d16f77ca909c4f20110329b8cdd5ad101e2afc0d58b06d416",
"output_directory": "output_win10",
"disk_size": "40960M",
"format": "qcow2",
"accelerator": "kvm",
"cpus": "2",
"memory": "4096",
"vm_name": "win10",
"net_device": "virtio-net",
"disk_interface": "virtio",
"floppy_files": [ "answer_files/win10/Autounattend.xml", "virtio/w10/core/*", "scripts/bootstrap.ps1" ],
"communicator": "winrm",
"winrm_username": "administrator",
"winrm_password": "{{user `administrator_password`}}",
"winrm_use_ntlm": true,
"shutdown_command": "powershell -ep bypass c:\\windows\\temp\\shutdown.ps1",
"headless": true
}
],
"provisioners": [
{
"type": "file",
"source": "scripts/shutdown.ps1",
"destination": "c:/windows/temp/shutdown.ps1"
},
{
"type": "file",
"source": "virtio/w10/extra",
"destination": "c:/windows/temp/"
},
{
"type": "powershell",
"script": "scripts/setupcomplete.ps1"
}
]
}
================================================
FILE: packer/win2012r2.json
================================================
{
"builders": [
{
"type": "qemu",
"name": "qemu-win2012r2",
"iso_url": "http://download.microsoft.com/download/6/2/A/62A76ABB-9990-4EFC-A4FE-C7D698DAEB96/9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_SERVER_EVAL_EN-US-IR3_SSS_X64FREE_EN-US_DV9.ISO",
"iso_checksum": "sha256:6612b5b1f53e845aacdf96e974bb119a3d9b4dcb5b82e65804ab7e534dc7b4d5",
"output_directory": "output_win2012r2",
"disk_size": "40960M",
"format": "qcow2",
"accelerator": "kvm",
"cpus": "2",
"memory": "4096",
"vm_name": "win2012r2",
"net_device": "virtio-net",
"disk_interface": "virtio",
"floppy_files": [ "answer_files/win2012r2/Autounattend.xml", "virtio/w8.1/core/*", "scripts/bootstrap.ps1" ],
"communicator": "winrm",
"winrm_username": "administrator",
"winrm_password": "{{user `administrator_password`}}",
"winrm_use_ntlm": true,
"shutdown_command": "powershell -ep bypass c:\\windows\\temp\\shutdown.ps1",
"headless": true
}
],
"provisioners": [
{
"type": "file",
"source": "scripts/shutdown.ps1",
"destination": "c:/windows/temp/shutdown.ps1"
},
{
"type": "file",
"source": "virtio/w8.1/extra",
"destination": "c:/windows/temp/"
},
{
"type": "powershell",
"script": "scripts/setupcomplete.ps1"
},
{
"type": "powershell",
"script": "scripts/win2012r2-dotnet-fix.ps1"
}
]
}
================================================
FILE: packer/win2016.json
================================================
{
"builders": [
{
"type": "qemu",
"name": "qemu-win2016",
"iso_url": "https://software-download.microsoft.com/download/pr/Windows_Server_2016_Datacenter_EVAL_en-us_14393_refresh.ISO",
"iso_checksum": "sha256:1ce702a578a3cb1ac3d14873980838590f06d5b7101c5daaccbac9d73f1fb50f",
"output_directory": "output_win2016",
"disk_size": "40960M",
"format": "qcow2",
"accelerator": "kvm",
"cpus": "2",
"memory": "4096",
"vm_name": "win2016",
"net_device": "virtio-net",
"disk_interface": "virtio",
"floppy_files": [ "answer_files/win2016/Autounattend.xml", "virtio/2k16/core/*", "scripts/bootstrap.ps1" ],
"communicator": "winrm",
"winrm_username": "administrator",
"winrm_password": "{{user `administrator_password`}}",
"winrm_use_ntlm": true,
"shutdown_command": "powershell -ep bypass c:\\windows\\temp\\shutdown.ps1",
"headless": true
}
],
"provisioners": [
{
"type": "file",
"source": "scripts/shutdown.ps1",
"destination": "c:/windows/temp/shutdown.ps1"
},
{
"type": "file",
"source": "virtio/2k16/extra",
"destination": "c:/windows/temp/"
},
{
"type": "powershell",
"script": "scripts/setupcomplete.ps1"
}
]
}
================================================
FILE: terraform/main.tf
================================================
provider "libvirt" {
uri = "qemu:///system"
}
locals {
mac_dc1 = "50:73:0F:31:81:E1"
mac_desktop12 = "50:73:0F:31:81:E2"
mac_graylog = "50:73:0F:31:81:F1"
mac_kali = "50:73:0F:31:81:F2"
}
resource "libvirt_network" "honeypot" {
name = "honeypot"
mode = "nat"
bridge = "honeybr0"
addresses = ["192.168.3.0/24"]
dhcp {
enabled = true
}
dns {
enabled = true
forwarders {
address = "192.168.3.100"
domain = "local"
}
}
xml {
xslt = file("network-dhcp-lease.xsl")
}
provisioner "local-exec" {
command = "/usr/bin/sudo /usr/sbin/iptables -I FORWARD -j DROP -i honeybr0 -d 192.168.0.0/16; /usr/bin/sudo /usr/sbin/iptables -I FORWARD -j ACCEPT -i honeybr0 -o honeybr0"
}
provisioner "local-exec" {
command = "/usr/bin/sudo /usr/sbin/iptables -D FORWARD -j DROP -i honeybr0 -d 192.168.0.0/16; /usr/bin/sudo /usr/sbin/iptables -D FORWARD -j ACCEPT -i honeybr0 -o honeybr0"
when = destroy
}
}
resource "libvirt_pool" "honeypot" {
name = "honeypot-pool"
type = "dir"
path = "/mnt/archive01/vm/honeypot-pool"
}
resource "libvirt_volume" "dc1-vol" {
pool = libvirt_pool.honeypot.name
name = "dc1-vol"
source = "../packer/output_win2016/win2016"
}
resource "libvirt_volume" "desktop12-vol" {
pool = libvirt_pool.honeypot.name
name = "desktop12-vol"
source = "../packer/output_win10/win10"
}
resource "libvirt_volume" "graylog-vol" {
pool = libvirt_pool.honeypot.name
name = "graylog-vol"
source = "../packer/output_graylog/graylog"
}
resource "libvirt_volume" "kali-vol" {
pool = libvirt_pool.honeypot.name
name = "kali-vol"
source = "../packer/output_kali/kali"
}
resource "libvirt_domain" "dc1-dom" {
provider = libvirt
name = "h-dc1"
memory = "4096"
vcpu = 4
disk {
volume_id = libvirt_volume.dc1-vol.id
}
network_interface {
network_id = libvirt_network.honeypot.id
hostname = "dc1"
mac = local.mac_dc1
}
xml {
xslt = file("timer-patch.xsl")
}
}
resource "libvirt_domain" "desktop12-dom" {
provider = libvirt
name = "h-desktop12"
memory = "4096"
vcpu = 4
disk {
volume_id = libvirt_volume.desktop12-vol.id
}
network_interface {
network_id = libvirt_network.honeypot.id
hostname = "desktop12"
mac = local.mac_desktop12
}
xml {
xslt = file("timer-patch.xsl")
}
}
resource "libvirt_domain" "graylog-dom" {
provider = libvirt
name = "h-graylog"
memory = "4096"
vcpu = 4
disk {
volume_id = libvirt_volume.graylog-vol.id
}
network_interface {
network_id = libvirt_network.honeypot.id
hostname = "graylog"
mac = local.mac_graylog
}
xml {
xslt = file("timer-patch.xsl")
}
}
resource "libvirt_domain" "kali-dom" {
provider = libvirt
name = "h-kali"
memory = "4096"
vcpu = 4
disk {
volume_id = libvirt_volume.kali-vol.id
}
network_interface {
network_id = libvirt_network.honeypot.id
hostname = "kali"
mac = local.mac_kali
}
xml {
xslt = file("timer-patch.xsl")
}
}
terraform {
required_version = ">= 0.13"
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
version = "0.6.14"
}
}
}
================================================
FILE: terraform/network-dhcp-lease.xsl
================================================
================================================
FILE: terraform/timer-patch.xsl
================================================