├── README.md ├── backend ├── docker-compose.yml ├── haproxy │ ├── Dockerfile │ ├── haproxy.cfg │ └── start_routing.sh └── teamserver │ ├── Dockerfile │ └── set_gateway.sh └── relay ├── docker-compose.yml └── haproxy └── haproxy.cfg /README.md: -------------------------------------------------------------------------------- 1 | # cnc-relay 2 | During a red team exercise it's common to set up a relaying infrastructure to seperate your external facing footprint from the actual command and control backend. Some of the popular light-weight options are to set up either HAProxy or NGINX on disposable cloud infrastructure and proxy traffic to an internal and/or secured host where an operator has access to the command and control framework. Even though this setup works in most cases, metadata such as the original source IP of a beacon is lost. 3 | 4 | This repository contains two docker environments that allows you to set up an example Command and Control environment with relays but still retain the original source IP of a beacon. More details can be found on my blogpost @ https://www.d3vzer0.com/retain-beacon-source-ip-with-haproxy-relays/ 5 | -------------------------------------------------------------------------------- /backend/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | teamserver: 4 | build: ./cobaltstrike 5 | cap_add: 6 | - NET_ADMIN 7 | - NET_RAW 8 | links: 9 | - haproxy 10 | environment: 11 | TS_IP: "" 12 | TS_PASSWORD: "" 13 | volumes: 14 | - "/opt/your_cs_dir:/opt/cobaltstrike" 15 | 16 | haproxy: 17 | build: ./haproxy 18 | cap_add: 19 | - NET_ADMIN 20 | - NET_RAW 21 | environment: 22 | TSIP: "teamserver" 23 | TSPORT: 80 24 | ADMINPORT: 50050 25 | ports: 26 | - "8080:8080" 27 | - "9090:9090" 28 | volumes: 29 | - "./haproxy:/etc/haproxy" 30 | -------------------------------------------------------------------------------- /backend/haproxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.9 2 | 3 | # Note: 4 | # Make sure that the host has the TPROX Kernel module enabled 5 | # modprobe xt_TPROXY && echo xt_TPROXY >> /etc/modules 6 | 7 | # Install generic buildtools 8 | RUN apk add build-base linux-headers iptables 9 | 10 | # Download and extract latest version of HAProxy 11 | RUN wget -O /tmp/haproxy-1.8.19.tar.gz http://www.haproxy.org/download/1.8/src/haproxy-1.8.19.tar.gz 12 | RUN tar -xzf /tmp/haproxy-1.8.19.tar.gz -C /tmp/ 13 | 14 | # Change working directory and build Haproxy with TPROX support 15 | WORKDIR /tmp/haproxy-1.8.19 16 | RUN make TARGET=linux26 USE_LINUX_TPROXY=1 17 | RUN make install target=linux26 18 | RUN cp /usr/local/sbin/haproxy /usr/sbin/haproxy 19 | 20 | # Change working directory 21 | WORKDIR /etc/haproxy 22 | 23 | # Copy and set iptables and route config 24 | COPY start_routing.sh . 25 | COPY haproxy.cfg . 26 | RUN ["chmod", "+x", "/etc/haproxy/start_routing.sh"] 27 | 28 | CMD ["./start_routing.sh"] -------------------------------------------------------------------------------- /backend/haproxy/haproxy.cfg: -------------------------------------------------------------------------------- 1 | global 2 | daemon 3 | log /dev/log local0 4 | log /dev/log local1 notice 5 | 6 | defaults 7 | log global 8 | mode http 9 | option tcplog 10 | maxconn 2000 11 | timeout connect 5000 12 | timeout client 5000 13 | timeout server 5000 14 | 15 | frontend proxy_listener 16 | mode tcp 17 | bind *:8080 accept-proxy 18 | use_backend listenserver 19 | 20 | frontend proxy_teamserver 21 | mode tcp 22 | bind *:9090 23 | use_backend teamserver 24 | 25 | backend listenserver 26 | mode tcp 27 | source 0.0.0.0 usesrc clientip 28 | server listenserver_1 ${TSIP}:${TSPORT} check 29 | 30 | backend teamserver 31 | mode tcp 32 | server teamserver_1 ${TSIP}:${ADMINPORT} check 33 | 34 | -------------------------------------------------------------------------------- /backend/haproxy/start_routing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Static sleep to wait for CS route to start up 4 | sleep 5 5 | 6 | # Set IPtables DIVERT before starting HAPROXY 7 | /sbin/iptables -t mangle -N DIVERT 8 | /sbin/iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT 9 | /sbin/iptables -t mangle -A DIVERT -j MARK --set-mark 1 10 | /sbin/iptables -t mangle -A DIVERT -j ACCEPT 11 | 12 | # Set IP routes and rules 13 | /sbin/ip rule add fwmark 1 lookup 100 14 | /sbin/ip route add local 0.0.0.0/0 dev lo table 100 15 | 16 | # Start Haproxy service 17 | /usr/sbin/haproxy -d -f /etc/haproxy/haproxy.cfg -------------------------------------------------------------------------------- /backend/teamserver/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11-stretch 2 | 3 | # Get dig for dynamic GW routing via HAPROXY 4 | RUN apt-get update && apt-get install -y dnsutils 5 | 6 | # Copy GW script to set GW to HAPROXY 7 | COPY set_gateway.sh /root/ 8 | RUN ["chmod", "+x", "/root/set_gateway.sh"] 9 | 10 | # Set defaults for teamserver 11 | ARG TS_IP=127.0.0.1 12 | ENV TS_IP="${TS_IP}" 13 | 14 | ARG TS_PASSWORD=you_should_change_this 15 | ENV TS_PASSWORD="${TS_PASSWORD}" 16 | 17 | # Run teamserver with default variables 18 | WORKDIR /opt/cobaltstrike 19 | 20 | CMD /root/set_gateway.sh && chmod +x ./teamserver && ./teamserver ${TS_IP} ${TS_PASSWORD} -------------------------------------------------------------------------------- /backend/teamserver/set_gateway.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Static sleep to wait for Haproxy route to start up 4 | sleep 5 5 | 6 | # Set gateway to Haproxy 7 | GW=`dig +short haproxy` 8 | /sbin/ip route del default 9 | /sbin/ip route add default via $GW -------------------------------------------------------------------------------- /relay/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | haproxy: 4 | image: haproxy:latest 5 | environment: 6 | PROXYIP: "" 7 | PROXYPORT: 8080 8 | volumes: 9 | - "./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg" -------------------------------------------------------------------------------- /relay/haproxy/haproxy.cfg: -------------------------------------------------------------------------------- 1 | global 2 | daemon 3 | log stdout local0 4 | log stdout local1 notice 5 | 6 | defaults 7 | log global 8 | mode tcp 9 | option tcplog 10 | maxconn 2000 11 | timeout connect 5000 12 | timeout client 5000 13 | timeout server 5000 14 | 15 | frontend reverse_tunnel 16 | bind *:80 17 | default_backend proxy_server 18 | 19 | backend proxy_server 20 | mode tcp 21 | server proxy_server1 ${PROXYIP}:${PROXYPORT} check send-proxy --------------------------------------------------------------------------------